/**
 * Domain Entity: LiveryTemplate
 *
 * Represents an admin-defined livery template for a specific car.
 * Contains base image and sponsor decal placements.
 */

import type { IEntity } from '@core/shared/domain';
import { RacingDomainValidationError, RacingDomainInvariantError } from '../errors/RacingDomainError';
import type { LiveryDecal } from '../value-objects/LiveryDecal';
import { LiveryTemplateId } from './LiveryTemplateId';
import { LeagueId } from './LeagueId';
import { SeasonId } from './season/SeasonId';
import { CarId } from '../value-objects/CarId';
import { ImageUrl } from './ImageUrl';
import { LiveryTemplateCreatedAt } from './LiveryTemplateCreatedAt';
import { LiveryTemplateUpdatedAt } from './LiveryTemplateUpdatedAt';

export class LiveryTemplate implements IEntity<LiveryTemplateId> {
  readonly id: LiveryTemplateId;
  readonly leagueId: LeagueId;
  readonly seasonId: SeasonId;
  readonly carId: CarId;
  readonly baseImageUrl: ImageUrl;
  readonly adminDecals: LiveryDecal[];
  readonly createdAt: LiveryTemplateCreatedAt;
  readonly updatedAt: LiveryTemplateUpdatedAt | undefined;

  private constructor(props: {
    id: LiveryTemplateId;
    leagueId: LeagueId;
    seasonId: SeasonId;
    carId: CarId;
    baseImageUrl: ImageUrl;
    adminDecals: LiveryDecal[];
    createdAt: LiveryTemplateCreatedAt;
    updatedAt?: LiveryTemplateUpdatedAt;
  }) {
    this.id = props.id;
    this.leagueId = props.leagueId;
    this.seasonId = props.seasonId;
    this.carId = props.carId;
    this.baseImageUrl = props.baseImageUrl;
    this.adminDecals = props.adminDecals;
    this.createdAt = props.createdAt;
    this.updatedAt = props.updatedAt;
  }

  static create(props: {
    id: string;
    leagueId: string;
    seasonId: string;
    carId: string;
    baseImageUrl: string;
    createdAt?: Date;
    adminDecals?: LiveryDecal[];
  }): LiveryTemplate {
    this.validate(props);

    const id = LiveryTemplateId.create(props.id);
    const leagueId = LeagueId.create(props.leagueId);
    const seasonId = SeasonId.create(props.seasonId);
    const carId = CarId.create(props.carId);
    const baseImageUrl = ImageUrl.create(props.baseImageUrl);
    const createdAt = LiveryTemplateCreatedAt.create(props.createdAt ?? new Date());

    return new LiveryTemplate({
      id,
      leagueId,
      seasonId,
      carId,
      baseImageUrl,
      adminDecals: props.adminDecals ?? [],
      createdAt,
    });
  }

  private static validate(props: {
    id: string;
    leagueId: string;
    seasonId: string;
    carId: string;
    baseImageUrl: string;
  }): void {
    if (!props.id || props.id.trim().length === 0) {
      throw new RacingDomainValidationError('LiveryTemplate ID is required');
    }

    if (!props.leagueId || props.leagueId.trim().length === 0) {
      throw new RacingDomainValidationError('LiveryTemplate leagueId is required');
    }

    if (!props.seasonId || props.seasonId.trim().length === 0) {
      throw new RacingDomainValidationError('LiveryTemplate seasonId is required');
    }

    if (!props.carId || props.carId.trim().length === 0) {
      throw new RacingDomainValidationError('LiveryTemplate carId is required');
    }

    if (!props.baseImageUrl || props.baseImageUrl.trim().length === 0) {
      throw new RacingDomainValidationError('LiveryTemplate baseImageUrl is required');
    }
  }

  /**
   * Add a decal to the template
   */
  addDecal(decal: LiveryDecal): LiveryTemplate {
    if (decal.type !== 'sponsor') {
      throw new RacingDomainInvariantError('Only sponsor decals can be added to admin template');
    }

    return new LiveryTemplate({
      ...this,
      adminDecals: [...this.adminDecals, decal],
      updatedAt: LiveryTemplateUpdatedAt.create(new Date()),
    });
  }

  /**
   * Remove a decal from the template
   */
  removeDecal(decalId: string): LiveryTemplate {
    const updatedDecals = this.adminDecals.filter(d => d.id !== decalId);

    if (updatedDecals.length === this.adminDecals.length) {
      throw new RacingDomainValidationError('Decal not found in template');
    }

    return new LiveryTemplate({
      ...this,
      adminDecals: updatedDecals,
      updatedAt: LiveryTemplateUpdatedAt.create(new Date()),
    });
  }

  /**
   * Update a decal position
   */
  updateDecal(decalId: string, updatedDecal: LiveryDecal): LiveryTemplate {
    const index = this.adminDecals.findIndex(d => d.id === decalId);

    if (index === -1) {
      throw new RacingDomainValidationError('Decal not found in template');
    }

    const updatedDecals = [...this.adminDecals];
    updatedDecals[index] = updatedDecal;

    return new LiveryTemplate({
      ...this,
      adminDecals: updatedDecals,
      updatedAt: LiveryTemplateUpdatedAt.create(new Date()),
    });
  }

  /**
   * Get all sponsor decals
   */
  getSponsorDecals(): LiveryDecal[] {
    return this.adminDecals.filter(d => d.type === 'sponsor');
  }

  /**
   * Check if template has sponsor decals
   */
  hasSponsorDecals(): boolean {
    return this.adminDecals.some(d => d.type === 'sponsor');
  }
}