// ============================================
// Editor Store - Game Editor State Management
// ============================================

import { goto } from "$app/navigation";
import { gameSession } from "./gameSession.svelte";
import { storage, STORAGE_KEYS } from "$lib/services";
import { validateGameData, type GameData } from "$lib/utils/validation";
import type {
    GameSettings,
    Team,
    Round,
    Category,
    Question,
    FinalRound,
    PointValuePreset,
} from "$lib/types/kuldvillak";
import { DEFAULT_SETTINGS } from "$lib/types/kuldvillak";

// ============================================
// Helper Functions (Pure, no state dependency)
// ============================================

function generateId(): string {
    return crypto.randomUUID();
}

function createQuestion(points: number): Question {
    return {
        id: generateId(),
        question: "",
        answer: "",
        points,
        isDailyDouble: false,
        isRevealed: false,
    };
}

function createCategory(settings: GameSettings, multiplier: number = 1): Category {
    return {
        id: generateId(),
        name: "",
        questions: settings.pointValues.map((p) => createQuestion(p * multiplier)),
    };
}

function createRound(name: string, multiplier: number, settings: GameSettings): Round {
    return {
        id: generateId(),
        name,
        categories: Array.from({ length: settings.categoriesPerRound }, () =>
            createCategory(settings, multiplier)
        ),
        pointMultiplier: multiplier,
    };
}

// ============================================
// Editor Store Class
// ============================================

class EditorStore {
    // Core game data
    gameName = $state("");
    settings = $state<GameSettings>({
        ...DEFAULT_SETTINGS,
        defaultTimerSeconds: 5,
        answerRevealSeconds: 5,
    });
    teams = $state<Team[]>([
        { id: generateId(), name: "Mängija 1", score: 0 },
        { id: generateId(), name: "Mängija 2", score: 0 },
    ]);
    rounds = $state<Round[]>([]);
    finalRound = $state<FinalRound>({
        category: "",
        question: "",
        answer: "",
    });

    // UI state
    isStarting = $state(false);
    private initialized = false;

    constructor() {
        // Initialize rounds with default names (will be set properly on load)
        this.rounds = [
            createRound("Villak", 1, DEFAULT_SETTINGS),
            createRound("Topeltvillak", 2, DEFAULT_SETTINGS),
        ];
    }

    // ============================================
    // Initialization & Persistence
    // ============================================

    /**
     * Load saved data from localStorage
     * Call this from onMount in the component
     */
    load() {
        if (this.initialized) return;
        this.initialized = true;

        const saved = storage.get<GameData>(STORAGE_KEYS.EDITOR_AUTOSAVE);
        if (saved) {
            const result = validateGameData(saved);
            if (result.success) {
                const data = result.data;
                this.gameName = data.name || "";
                this.settings = {
                    ...DEFAULT_SETTINGS,
                    ...data.settings,
                };
                this.teams = data.teams;
                this.rounds = data.rounds;
                this.finalRound = data.finalRound || {
                    category: "",
                    question: "",
                    answer: "",
                };
            }
        }
    }

    /**
     * Save current state to localStorage
     */
    save() {
        const data: GameData = {
            name: this.gameName,
            settings: $state.snapshot(this.settings),
            teams: $state.snapshot(this.teams),
            rounds: $state.snapshot(this.rounds),
            finalRound: $state.snapshot(this.finalRound),
        };
        storage.set(STORAGE_KEYS.EDITOR_AUTOSAVE, data);
    }

    /**
     * Clear saved data from localStorage
     */
    clearSaved() {
        storage.remove(STORAGE_KEYS.EDITOR_AUTOSAVE);
    }

    // ============================================
    // Validation
    // ============================================

    /**
     * Validate game configuration
     * @returns Error message string or null if valid
     */
    validateGame(): string | null {
        if (this.teams.length < 2) {
            return "At least 2 players required";
        }

        for (let i = 0; i < this.rounds.length; i++) {
            const hasQuestions = this.rounds[i].categories.some((cat) =>
                cat.questions.some((q) => q.question.trim())
            );
            if (!hasQuestions) {
                return `Round ${i + 1} needs at least one question`;
            }
        }

        if (this.settings.enableFinalRound && !this.finalRound.question.trim()) {
            return "Final round question is required";
        }

        return null;
    }

    // ============================================
    // Game Actions
    // ============================================

    /**
     * Start the game - validates, initializes game session, navigates to play
     * @returns Object with success status and optional error message
     */
    async startGame(): Promise<{ success: boolean; error?: string }> {
        const error = this.validateGame();
        if (error) {
            return { success: false, error };
        }

        this.isStarting = true;
        try {
            gameSession.startGame({
                name: this.gameName,
                settings: $state.snapshot(this.settings),
                teams: $state.snapshot(this.teams),
                rounds: $state.snapshot(this.rounds),
                finalRound: this.settings.enableFinalRound
                    ? $state.snapshot(this.finalRound)
                    : null,
            });
            gameSession.openProjector();
            await goto("/kuldvillak/play");
            return { success: true };
        } catch (err) {
            this.isStarting = false;
            return { success: false, error: String(err) };
        }
    }

    /**
     * Export game to JSON file for download
     */
    exportGame(): { blob: Blob; filename: string } {
        const game = {
            name: this.gameName,
            settings: $state.snapshot(this.settings),
            teams: $state.snapshot(this.teams),
            rounds: $state.snapshot(this.rounds),
            finalRound: $state.snapshot(this.finalRound),
        };
        const blob = new Blob([JSON.stringify(game, null, 2)], {
            type: "application/json",
        });
        const filename = `${this.gameName.replace(/\s+/g, "_") || "game"}.json`;
        return { blob, filename };
    }

    /**
     * Import game from JSON data
     * @returns true if successful, error message if failed
     */
    importGame(data: unknown): true | string {
        const result = validateGameData(data);
        if (!result.success) {
            return result.error;
        }

        const game = result.data;
        this.gameName = game.name || "Loaded Game";
        this.settings = {
            ...DEFAULT_SETTINGS,
            ...game.settings,
        };
        this.teams = game.teams;
        this.rounds = game.rounds;
        this.finalRound = game.finalRound || {
            category: "",
            question: "",
            answer: "",
        };

        return true;
    }

    /**
     * Reset to default state
     */
    reset(round1Name: string, round2Name: string) {
        this.settings = {
            ...DEFAULT_SETTINGS,
            defaultTimerSeconds: 5,
            answerRevealSeconds: 5,
        };
        this.teams = [
            { id: generateId(), name: "Mängija 1", score: 0 },
            { id: generateId(), name: "Mängija 2", score: 0 },
        ];
        this.rounds = [
            createRound(round1Name, 1, DEFAULT_SETTINGS),
            createRound(round2Name, 2, DEFAULT_SETTINGS),
        ];
        this.finalRound = { category: "", question: "", answer: "" };
        this.gameName = "";
        this.clearSaved();
    }

    // ============================================
    // Team Management
    // ============================================

    addTeam() {
        if (this.teams.length >= 6) return;
        this.teams = [
            ...this.teams,
            { id: generateId(), name: `Mängija ${this.teams.length + 1}`, score: 0 },
        ];
    }

    removeTeam(id: string) {
        if (this.teams.length <= 2) return;
        this.teams = this.teams.filter((t) => t.id !== id);
    }

    updateTeamName(id: string, name: string) {
        const team = this.teams.find((t) => t.id === id);
        if (team) {
            team.name = name;
        }
    }

    // ============================================
    // Round Management
    // ============================================

    setRoundCount(count: 1 | 2, round2Name: string) {
        this.settings.numberOfRounds = count;
        if (count === 1 && this.rounds.length > 1) {
            this.rounds = [this.rounds[0]];
            this.settings.dailyDoublesPerRound = [this.settings.dailyDoublesPerRound[0]];
        } else if (count === 2 && this.rounds.length === 1) {
            this.rounds = [...this.rounds, createRound(round2Name, 2, this.settings)];
            this.settings.dailyDoublesPerRound = [
                this.settings.dailyDoublesPerRound[0],
                2,
            ];
        }
        this.updateQuestionPoints();
    }

    getPointsForRound(preset: PointValuePreset, roundIndex: number): number[] {
        const base = [10, 20, 30, 40, 50];
        const multiplier = roundIndex + 1;
        if (preset === "round1") return base.map((v) => v * multiplier);
        return this.settings.pointValues.map((v) => v * multiplier);
    }

    updatePreset(preset: PointValuePreset) {
        this.settings.pointValuePreset = preset;
        if (preset === "round1") {
            this.settings.pointValues = [10, 20, 30, 40, 50];
        }
        this.updateQuestionPoints();
    }

    updateQuestionPoints() {
        this.rounds.forEach((round, ri) => {
            const points = this.getPointsForRound(this.settings.pointValuePreset, ri);
            round.categories.forEach((cat) =>
                cat.questions.forEach((q, i) => {
                    q.points = points[i] ?? q.points;
                })
            );
        });
        this.rounds = [...this.rounds];
    }

    // ============================================
    // Category Management
    // ============================================

    updateCategoryName(roundIndex: number, catIndex: number, name: string) {
        if (this.rounds[roundIndex]?.categories[catIndex]) {
            this.rounds[roundIndex].categories[catIndex].name = name;
        }
    }

    // ============================================
    // Question Management
    // ============================================

    getQuestion(roundIndex: number, catIndex: number, qIndex: number): Question | null {
        return this.rounds[roundIndex]?.categories[catIndex]?.questions[qIndex] ?? null;
    }

    updateQuestion(
        roundIndex: number,
        catIndex: number,
        qIndex: number,
        updates: Partial<Pick<Question, "question" | "answer" | "imageUrl" | "isDailyDouble">>
    ) {
        const q = this.getQuestion(roundIndex, catIndex, qIndex);
        if (q) {
            Object.assign(q, updates);
            this.rounds = [...this.rounds];
        }
    }

    countDailyDoubles(roundIndex: number): number {
        return this.rounds[roundIndex]?.categories.reduce(
            (sum, cat) => sum + cat.questions.filter((q) => q.isDailyDouble).length,
            0
        ) ?? 0;
    }

    toggleDailyDouble(roundIndex: number, catIndex: number, qIndex: number): boolean {
        const q = this.getQuestion(roundIndex, catIndex, qIndex);
        if (!q) return false;

        const maxDD = this.settings.dailyDoublesPerRound[roundIndex] ?? 1;
        const currentCount = this.countDailyDoubles(roundIndex);

        if (q.isDailyDouble) {
            q.isDailyDouble = false;
            this.rounds = [...this.rounds];
            return true;
        } else if (currentCount < maxDD) {
            q.isDailyDouble = true;
            this.rounds = [...this.rounds];
            return true;
        }
        return false;
    }

    // ============================================
    // Final Round Management
    // ============================================

    updateFinalRound(updates: Partial<FinalRound>) {
        this.finalRound = { ...this.finalRound, ...updates };
    }

    // ============================================
    // Derived State
    // ============================================

    get canAddTeam(): boolean {
        return this.teams.length < 6;
    }

    get canRemoveTeam(): boolean {
        return this.teams.length > 2;
    }

    get totalQuestions(): number {
        return this.rounds.reduce(
            (total, round) =>
                total + round.categories.reduce(
                    (catTotal, cat) => catTotal + cat.questions.length,
                    0
                ),
            0
        );
    }

    get filledQuestions(): number {
        return this.rounds.reduce(
            (total, round) =>
                total + round.categories.reduce(
                    (catTotal, cat) =>
                        catTotal + cat.questions.filter((q) => q.question.trim()).length,
                    0
                ),
            0
        );
    }
}

export const editorStore = new EditorStore();
