<script lang="ts">
    import {
        LevelCalculator,
        type LevelCalculatorOutput,
        type Standards,
    } from "@blade-and-brawn/calculator";
    import {
        Activity,
        Attribute,
        Gender,
        lbToKg,
        range,
        type ActivityPerformance,
        type Player,
    } from "@blade-and-brawn/domain";

    interface CalcData {
        levels?: LevelCalculatorOutput;
        player: Player;
        activityPerformances: ActivityPerformance[];
    }

    interface Props {
        allStandards: Standards;
    }

    const { allStandards }: Props = $props();

    const levelCalculator = $derived(new LevelCalculator(allStandards));

    let calculations = $state([] as CalcData[]);

    $effect(() => {
        for (const calculation of calculations) {
            calculation.levels = levelCalculator.calculate(
                calculation.player,
                calculation.activityPerformances,
            );
        }
    });

    $effect(() => {
        const savedCalcs = localStorage.getItem("calculations");
        if (savedCalcs) calculations = JSON.parse(savedCalcs);
    });

    $effect(() => {
        localStorage.setItem("calculations", JSON.stringify(calculations));
    });

    $inspect(calculations[0]);

    const createCalculation = function (name: string) {
        return {
            player: {
                name: name,
                metrics: {
                    age: 18,
                    weight: lbToKg(180),
                    gender: Gender.Male,
                },
            },
            activityPerformances: Object.values(Activity).map((a) => ({
                activity: a,
                performance: 0,
            })),
        };
    };

    function downloadObject(obj: unknown, filename = "data.json") {
        const json = JSON.stringify(obj, null, 2);
        const blob = new Blob([json], { type: "application/json" });
        const url = URL.createObjectURL(blob);

        const a = document.createElement("a");
        a.href = url;
        a.download = filename;
        document.body.appendChild(a);
        a.click();

        a.remove();
        URL.revokeObjectURL(url);
    }

    const formatMs = (ms: number) => {
        const total = Math.floor(ms / 1000);
        const m = Math.floor(total / 60);
        const s = total % 60;
        return `${m}m ${s}s`;
    };
    const inchesToFeetInches = (inches: number) => {
        const ft = Math.floor(inches / 12);
        const rem = inches - ft * 12;
        const whole = Math.floor(rem);
        const isHalf = Math.abs(rem - whole - 0.5) < 1e-9;
        const inchLabel = isHalf ? `${whole}½` : `${whole}`;
        return `${ft}' ${inchLabel}"`;
    };

    const formatSeconds = (ms: number) => (ms / 1000).toFixed(2) + " seconds";

    const performanceOptionsFromActivity = function (activity: Activity) {
        const options: { name: string; value: string }[] = [];
        switch (activity) {
            case Activity.BackSquat:
            case Activity.Deadlift:
            case Activity.BenchPress:
                for (let i = 0; i < 600; ++i) {
                    options.push({
                        name: String(i) + " lb",
                        value: String(lbToKg(i)),
                    });
                }
                break;

            case Activity.Run: {
                const MAX_MIN = 30;
                for (let ms = 0; ms <= MAX_MIN * 60_000; ms += 1_000) {
                    options.push({ name: formatMs(ms), value: String(ms) });
                }
                break;
            }

            case Activity.BroadJump: {
                const MAX_INCHES = 15 * 12 + 5;
                for (let halfStep = 0; halfStep <= MAX_INCHES * 2; halfStep++) {
                    const inches = halfStep / 2;
                    options.push({
                        name: inchesToFeetInches(inches),
                        value: (inches * 2.54).toFixed(1),
                    });
                }
                break;
            }

            case Activity.ConeDrill: {
                const MIN_MS = 5_000;
                const MAX_MS = 20_000;
                for (let ms = MIN_MS; ms <= MAX_MS; ms += 10) {
                    options.push({
                        name: formatSeconds(ms),
                        value: String(ms),
                    });
                }
                break;
            }
        }
        return options;
    };
</script>

<div class="mt-5 mb-5 flex w-full">
    <div class="ml-auto">
        <button
            onclick={() =>
                calculations.push(
                    createCalculation(String(calculations.length)),
                )}
            class="btn btn-primary">New</button
        >
        <button
            onclick={() => downloadObject(calculations)}
            class="btn btn-secondary">Export</button
        >
    </div>
</div>

<section
    class="w-full px-3 grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4"
>
    {#each calculations as calculation, index}
        <div
            class="card card-compact bg-base-200 p-4 shadow-lg max-w-sm w-full"
        >
            <div class="card-body gap-4 p-4">
                <input
                    class="input input-bordered input-sm w-full"
                    type="text"
                    bind:value={calculation.player.name}
                    placeholder="Player name"
                />

                <ul
                    class="bg-base-100 rounded-box shadow-xs divide-y divide-base-300"
                >
                    <li class="p-3">
                        <div class="flex items-center justify-between">
                            <div class="font-semibold text-sm">OVERALL</div>
                            <div class="badge badge-neutral badge-xs">
                                {calculation?.levels?.player || "N/A"}
                            </div>
                        </div>
                    </li>

                    {#each Object.values(Attribute) as attribute}
                        <li class="p-3">
                            <div class="flex items-center justify-between">
                                <div class="opacity-80 text-sm">
                                    {attribute}
                                </div>
                                <div class="badge badge-ghost badge-xs">
                                    {calculation?.levels?.attributes?.[
                                        attribute
                                    ] || "N/A"}
                                </div>
                            </div>
                        </li>
                    {/each}
                </ul>

                <fieldset
                    class="fieldset bg-base-200/60 rounded-lg"
                    onchange={() =>
                        (calculation.levels = levelCalculator.calculate(
                            calculation.player,
                            calculation.activityPerformances,
                        ))}
                >
                    <div class="grid grid-cols-1 md:grid-cols-3 gap-3">
                        <label class="form-control">
                            <span class="label mb-1 text-xs">Gender</span>
                            <select
                                class="select select-bordered select-sm w-full"
                                bind:value={calculation.player.metrics.gender}
                            >
                                {#each Object.values(Gender) as gender}
                                    <option value={gender}>{gender}</option>
                                {/each}
                            </select>
                        </label>

                        <label class="form-control">
                            <span class="label mb-1 text-xs">Age</span>
                            <input
                                class="input input-bordered input-sm w-full"
                                type="number"
                                min="1"
                                max="100"
                                step="1"
                                bind:value={calculation.player.metrics.age}
                            />
                        </label>

                        <label class="form-control">
                            <span class="label mb-1 text-xs">Weight</span>
                            <select
                                class="select select-bordered select-sm w-full"
                                bind:value={calculation.player.metrics.weight}
                            >
                                {#each range(400) as weight}
                                    <option value={String(lbToKg(weight))}
                                        >{weight}</option
                                    >
                                {/each}
                            </select>
                        </label>
                    </div>
                </fieldset>

                <fieldset
                    class="fieldset bg-base-200/60 rounded-lg"
                    onchange={() =>
                        (calculation.levels = levelCalculator.calculate(
                            calculation.player,
                            calculation.activityPerformances,
                        ))}
                >
                    <div class="grid grid-cols-2 gap-3">
                        {#each calculation.activityPerformances as activityPerformance}
                            <label class="form-control space-y-1">
                                <span class="label mb-1 text-xs">
                                    {activityPerformance.activity}
                                </span>
                                <select
                                    class="select select-bordered select-sm w-full"
                                    bind:value={activityPerformance.performance}
                                >
                                    {#each performanceOptionsFromActivity(activityPerformance.activity) as option}
                                        <option value={option.value}
                                            >{option.name}</option
                                        >
                                    {/each}
                                </select>
                            </label>
                        {/each}
                    </div>
                </fieldset>
            </div>
            <button
                onclick={() =>
                    confirm(`Delete ${calculation.player.name}?`) &&
                    calculations.splice(index, 1)}
                class="btn btn-error btn-sm w-1/4">Delete</button
            >
        </div>
    {/each}
</section>
