import { faker } from '@faker-js/faker';
/**
* Core Domain Service: MediaGenerationService
*
* Encapsulates business logic for generating media assets (SVGs) using Faker.
* Ensures deterministic results by seeding Faker with entity IDs.
*/
export class MediaGenerationService {
/**
* Generates a deterministic SVG avatar for a driver
*/
generateDriverAvatar(driverId: string): string {
faker.seed(this.hashCode(driverId));
const firstName = faker.person.firstName();
const lastName = faker.person.lastName();
const initials = ((firstName?.[0] || 'D') + (lastName?.[0] || 'R')).toUpperCase();
const primaryColor = faker.color.rgb({ format: 'hex' });
const secondaryColor = faker.color.rgb({ format: 'hex' });
const patterns = ['gradient', 'stripes', 'circles', 'diamond'];
const pattern = faker.helpers.arrayElement(patterns);
let patternSvg = '';
switch (pattern) {
case 'gradient':
patternSvg = `
`;
break;
case 'stripes':
patternSvg = `
`;
break;
case 'circles':
patternSvg = `
`;
break;
case 'diamond':
patternSvg = `
`;
break;
}
return `
`;
}
/**
* Generates a deterministic SVG logo for a team
* Now includes team name initials for better branding
*/
generateTeamLogo(teamId: string): string {
faker.seed(this.hashCode(teamId));
const primaryColor = faker.color.rgb({ format: 'hex' });
const secondaryColor = faker.color.rgb({ format: 'hex' });
// Generate deterministic initials from seeded faker data
// This creates consistent initials for the same teamId
const adjective = faker.company.buzzAdjective();
const noun = faker.company.catchPhraseNoun();
const initials = ((adjective?.[0] || 'T') + (noun?.[0] || 'M')).toUpperCase();
const shapes = ['circle', 'square', 'triangle', 'hexagon'];
const shape = faker.helpers.arrayElement(shapes);
let shapeSvg = '';
switch (shape) {
case 'circle':
shapeSvg = ``;
break;
case 'square':
shapeSvg = ``;
break;
case 'triangle':
shapeSvg = ``;
break;
case 'hexagon':
shapeSvg = ``;
break;
}
return `
`;
}
/**
* Generates a deterministic SVG logo for a league
* Updated to use the same faker style as team logos for consistency
*/
generateLeagueLogo(leagueId: string): string {
faker.seed(this.hashCode(leagueId));
const primaryColor = faker.color.rgb({ format: 'hex' });
const secondaryColor = faker.color.rgb({ format: 'hex' });
// Generate deterministic initials from seeded faker data
// This creates consistent initials for the same leagueId
const adjective = faker.company.buzzAdjective();
const noun = faker.company.catchPhraseNoun();
const initials = ((adjective?.[0] || 'L') + (noun?.[0] || 'G')).toUpperCase();
const shapes = ['circle', 'square', 'triangle', 'hexagon'];
const shape = faker.helpers.arrayElement(shapes);
let shapeSvg = '';
switch (shape) {
case 'circle':
shapeSvg = ``;
break;
case 'square':
shapeSvg = ``;
break;
case 'triangle':
shapeSvg = ``;
break;
case 'hexagon':
shapeSvg = ``;
break;
}
return `
`;
}
/**
* Generates a deterministic SVG cover for a league
*/
generateLeagueCover(leagueId: string): string {
faker.seed(this.hashCode(leagueId));
const primaryColor = faker.color.rgb({ format: 'hex' });
const secondaryColor = faker.color.rgb({ format: 'hex' });
return `
`;
}
/**
* Generates a simple PNG placeholder (base64 encoded)
* In production, this would serve actual PNG files from public assets
*/
generateDefaultPNG(variant: string): Buffer {
// For now, generate a simple colored square as PNG placeholder
// In production, this would read actual PNG files
faker.seed(this.hashCode(variant));
const color = faker.color.rgb({ format: 'hex' });
// Parse the hex color
const r = parseInt(color.slice(1, 3), 16);
const g = parseInt(color.slice(3, 5), 16);
const b = parseInt(color.slice(5, 7), 16);
// Create a minimal valid PNG (1x1 pixel) with the variant color
// This is a very basic PNG - in production you'd serve real files
// PNG header and minimal data for a 1x1 RGB pixel
const pngHeader = Buffer.from([
// PNG signature
0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
// IHDR chunk (13 bytes)
0x00, 0x00, 0x00, 0x0D, // Length: 13
0x49, 0x48, 0x44, 0x52, // Type: IHDR
0x00, 0x00, 0x00, 0x01, // Width: 1
0x00, 0x00, 0x00, 0x01, // Height: 1
0x08, // Bit depth: 8
0x02, // Color type: RGB
0x00, // Compression method
0x00, // Filter method
0x00, // Interlace method
0x00, 0x00, 0x00, 0x00, // CRC (placeholder, simplified)
// IDAT chunk (image data)
0x00, 0x00, 0x00, 0x07, // Length: 7
0x49, 0x44, 0x41, 0x54, // Type: IDAT
0x08, 0x1D, // Zlib header
0x01, // Deflate block header
r, g, b, // RGB pixel data
0x00, 0x00, 0x00, 0x00, // CRC (placeholder)
// IEND chunk
0x00, 0x00, 0x00, 0x00, // Length: 0
0x49, 0x45, 0x4E, 0x44, // Type: IEND
0xAE, 0x42, 0x60, 0x82 // CRC (placeholder)
]);
return pngHeader;
}
private hashCode(str: string): number {
let hash = 0;
for (let i = 0; i < str.length; i++) {
const char = str.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash = hash & hash;
}
return Math.abs(hash);
}
}