import type { CreateLeagueInputDTO } from '@/lib/types/generated/CreateLeagueInputDTO';
import { LeagueWizardValidationMessages } from '@/lib/display-objects/LeagueWizardValidationMessages';

export type WizardStep = 1 | 2 | 3 | 4 | 5 | 6 | 7;

export interface WizardErrors {
  basics?: {
    name?: string;
    description?: string;
    visibility?: string;
  };
  structure?: {
    maxDrivers?: string;
    maxTeams?: string;
    driversPerTeam?: string;
  };
  timings?: {
    qualifyingMinutes?: string;
    mainRaceMinutes?: string;
    roundsPlanned?: string;
  };
  scoring?: {
    patternId?: string;
  };
  submit?: string;
}

type LeagueWizardFormData = {
  leagueId: string | undefined;
  basics: {
    name: string;
    description?: string;
    visibility: 'public' | 'private' | 'unlisted';
    gameId: string;
  };
  structure: {
    mode: 'solo' | 'fixedTeams';
    maxDrivers?: number;
    maxTeams?: number;
    driversPerTeam?: number;
  };
  championships: {
    enableDriverChampionship: boolean;
    enableTeamChampionship: boolean;
    enableNationsChampionship: boolean;
    enableTrophyChampionship: boolean;
  };
  scoring: {
    patternId?: string;
    customScoringEnabled?: boolean;
  };
  dropPolicy: {
    strategy: 'none' | 'bestNResults' | 'dropWorstN';
    n?: number;
  };
  timings: {
    practiceMinutes?: number;
    qualifyingMinutes?: number;
    sprintRaceMinutes?: number;
    mainRaceMinutes?: number;
    sessionCount?: number;
    roundsPlanned?: number;
    raceDayOfWeek?: number;
    raceTimeUtc?: string;
  };
  stewarding: {
    decisionMode: 'owner_only' | 'admin_vote' | 'steward_panel';
    requiredVotes?: number;
    requireDefense: boolean;
    defenseTimeLimit: number;
    voteTimeLimit: number;
    protestDeadlineHours: number;
    stewardingClosesHours: number;
    notifyAccusedOnProtest: boolean;
    notifyOnVoteRequired: boolean;
  };
};

export class LeagueWizardCommandModel {
  leagueId: string | undefined;
  basics: LeagueWizardFormData['basics'];
  structure: LeagueWizardFormData['structure'];
  championships: LeagueWizardFormData['championships'];
  scoring: LeagueWizardFormData['scoring'];
  dropPolicy: LeagueWizardFormData['dropPolicy'];
  timings: LeagueWizardFormData['timings'];
  stewarding: LeagueWizardFormData['stewarding'];

  constructor(initial: Partial<LeagueWizardFormData> = {}) {
    this.leagueId = initial.leagueId;
    this.basics = {
      name: '',
      description: '',
      visibility: 'public',
      gameId: '',
      ...initial.basics,
    };
    this.structure = {
      mode: 'solo',
      ...initial.structure,
    };
    this.championships = {
      enableDriverChampionship: true,
      enableTeamChampionship: false,
      enableNationsChampionship: false,
      enableTrophyChampionship: false,
      ...initial.championships,
    };
    this.scoring = {
      ...initial.scoring,
    };
    this.dropPolicy = {
      strategy: 'none',
      ...initial.dropPolicy,
    };
    this.timings = {
      ...initial.timings,
    };
    this.stewarding = {
      decisionMode: 'owner_only',
      requireDefense: false,
      defenseTimeLimit: 24,
      voteTimeLimit: 48,
      protestDeadlineHours: 24,
      stewardingClosesHours: 168,
      notifyAccusedOnProtest: true,
      notifyOnVoteRequired: true,
      ...initial.stewarding,
    };
  }

  validateStep(step: WizardStep): WizardErrors {
    const errors: WizardErrors = {};

    // Step 1: Basics
    if (step === 1) {
      const basicsErrors: NonNullable<WizardErrors['basics']> = {};

      if (!this.basics.name || this.basics.name.trim().length === 0) {
        basicsErrors.name = LeagueWizardValidationMessages.LEAGUE_NAME_REQUIRED;
      } else if (this.basics.name.length < 3) {
        basicsErrors.name = LeagueWizardValidationMessages.LEAGUE_NAME_TOO_SHORT;
      } else if (this.basics.name.length > 100) {
        basicsErrors.name = LeagueWizardValidationMessages.LEAGUE_NAME_TOO_LONG;
      }

      if (this.basics.description && this.basics.description.length > 500) {
        basicsErrors.description = LeagueWizardValidationMessages.DESCRIPTION_TOO_LONG;
      }

      if (Object.keys(basicsErrors).length > 0) {
        errors.basics = basicsErrors;
      }
    }

    // Step 2: Visibility
    if (step === 2) {
      const basicsErrors: NonNullable<WizardErrors['basics']> = {};

      if (!this.basics.visibility) {
        basicsErrors.visibility = LeagueWizardValidationMessages.VISIBILITY_REQUIRED;
      }

      if (Object.keys(basicsErrors).length > 0) {
        errors.basics = basicsErrors;
      }
    }

    // Step 3: Structure
    if (step === 3) {
      const structureErrors: NonNullable<WizardErrors['structure']> = {};

      if (this.structure.mode === 'solo') {
        if (!this.structure.maxDrivers || this.structure.maxDrivers <= 0) {
          structureErrors.maxDrivers = LeagueWizardValidationMessages.MAX_DRIVERS_INVALID_SOLO;
        } else if (this.structure.maxDrivers > 100) {
          structureErrors.maxDrivers = LeagueWizardValidationMessages.MAX_DRIVERS_TOO_HIGH;
        }
      } else if (this.structure.mode === 'fixedTeams') {
        if (!this.structure.maxTeams || this.structure.maxTeams <= 0) {
          structureErrors.maxTeams = LeagueWizardValidationMessages.MAX_TEAMS_INVALID_TEAM;
        }
        if (!this.structure.driversPerTeam || this.structure.driversPerTeam <= 0) {
          structureErrors.driversPerTeam = LeagueWizardValidationMessages.DRIVERS_PER_TEAM_INVALID;
        }
      }
      if (Object.keys(structureErrors).length > 0) {
        errors.structure = structureErrors;
      }
    }

    // Step 4: Timings
    if (step === 4) {
      const timingsErrors: NonNullable<WizardErrors['timings']> = {};
      if (!this.timings.qualifyingMinutes || this.timings.qualifyingMinutes <= 0) {
        timingsErrors.qualifyingMinutes = LeagueWizardValidationMessages.QUALIFYING_DURATION_INVALID;
      }
      if (!this.timings.mainRaceMinutes || this.timings.mainRaceMinutes <= 0) {
        timingsErrors.mainRaceMinutes = LeagueWizardValidationMessages.MAIN_RACE_DURATION_INVALID;
      }
      if (Object.keys(timingsErrors).length > 0) {
        errors.timings = timingsErrors;
      }
    }

    // Step 5: Scoring
    if (step === 5) {
      const scoringErrors: NonNullable<WizardErrors['scoring']> = {};
      if (!this.scoring.patternId && !this.scoring.customScoringEnabled) {
        scoringErrors.patternId = LeagueWizardValidationMessages.SCORING_PRESET_OR_CUSTOM_REQUIRED;
      }
      if (Object.keys(scoringErrors).length > 0) {
        errors.scoring = scoringErrors;
      }
    }

    return errors;
  }

  validateAll(): WizardErrors {
    const aggregate: WizardErrors = {};

    const merge = (next: WizardErrors) => {
      if (next.basics) {
        aggregate.basics = { ...aggregate.basics, ...next.basics };
      }
      if (next.structure) {
        aggregate.structure = { ...aggregate.structure, ...next.structure };
      }
      if (next.timings) {
        aggregate.timings = { ...aggregate.timings, ...next.timings };
      }
      if (next.scoring) {
        aggregate.scoring = { ...aggregate.scoring, ...next.scoring };
      }
      if (next.submit) {
        aggregate.submit = next.submit;
      }
    };

    merge(this.validateStep(1));
    merge(this.validateStep(2));
    merge(this.validateStep(3));
    merge(this.validateStep(4));
    merge(this.validateStep(5));

    return aggregate;
  }

  static hasWizardErrors(errors: WizardErrors): boolean {
    return Object.keys(errors).some((key) => {
      const value = errors[key as keyof WizardErrors];
      if (!value) return false;
      if (typeof value === 'string') return true;
      return Object.keys(value).length > 0;
    });
  }

  applyScoringPreset(patternId: string): void {
    this.scoring = {
      ...this.scoring,
      patternId,
      customScoringEnabled: false,
    };
    // Timing defaults are applied by the UI using the selected preset's `defaultTimings` from the API.
  }

  toCreateLeagueCommand(ownerId: string): CreateLeagueInputDTO {
    return {
      name: this.basics.name.trim(),
      description: this.basics.description?.trim() ?? '',
      // API currently only supports public/private. Treat unlisted as private for now.
      visibility: this.basics.visibility === 'public' ? 'public' : 'private',
      ownerId,
    };
  }

  // Static methods for backward compatibility with component usage
  static validateLeagueWizardStep(form: LeagueWizardFormData, step: WizardStep): WizardErrors {
    const instance = new LeagueWizardCommandModel(form);
    return instance.validateStep(step);
  }

  static validateAllLeagueWizardSteps(form: LeagueWizardFormData): WizardErrors {
    const instance = new LeagueWizardCommandModel(form);
    return instance.validateAll();
  }

  static applyScoringPresetToConfig(form: LeagueWizardFormData, patternId: string): LeagueWizardFormData {
    const instance = new LeagueWizardCommandModel(form);
    instance.applyScoringPreset(patternId);
    return {
      leagueId: instance.leagueId,
      basics: instance.basics,
      structure: instance.structure,
      championships: instance.championships,
      scoring: instance.scoring,
      dropPolicy: instance.dropPolicy,
      timings: instance.timings,
      stewarding: instance.stewarding,
    };
  }
}
