import { useEffect, useState, useCallback } from "react";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
import { toast } from "sonner";

// Sentinel value for "none" selection
export const NONE_VALUE = "__none__";

// Schema definition matching backend config
const bigIntStringSchema = z.coerce.string()
    .refine((val) => /^\d+$/.test(val), { message: "Must be a valid integer" });

export const formSchema = z.object({
    leveling: z.object({
        base: z.number(),
        exponent: z.number(),
        chat: z.object({
            cooldownMs: z.number(),
            minXp: z.number(),
            maxXp: z.number(),
        })
    }),
    economy: z.object({
        daily: z.object({
            amount: bigIntStringSchema,
            streakBonus: bigIntStringSchema,
            weeklyBonus: bigIntStringSchema,
            cooldownMs: z.number(),
        }),
        transfers: z.object({
            allowSelfTransfer: z.boolean(),
            minAmount: bigIntStringSchema,
        }),
        exam: z.object({
            multMin: z.number(),
            multMax: z.number(),
        })
    }),
    inventory: z.object({
        maxStackSize: bigIntStringSchema,
        maxSlots: z.number(),
    }),
    commands: z.record(z.string(), z.boolean()).optional(),
    lootdrop: z.object({
        activityWindowMs: z.number(),
        minMessages: z.number(),
        spawnChance: z.number(),
        cooldownMs: z.number(),
        reward: z.object({
            min: z.number(),
            max: z.number(),
            currency: z.string(),
        })
    }),
    studentRole: z.string().optional(),
    visitorRole: z.string().optional(),
    colorRoles: z.array(z.string()).default([]),
    welcomeChannelId: z.string().optional(),
    welcomeMessage: z.string().optional(),
    feedbackChannelId: z.string().optional(),
    terminal: z.object({
        channelId: z.string(),
        messageId: z.string()
    }).optional(),
    moderation: z.object({
        prune: z.object({
            maxAmount: z.number(),
            confirmThreshold: z.number(),
            batchSize: z.number(),
            batchDelayMs: z.number(),
        }),
        cases: z.object({
            dmOnWarn: z.boolean(),
            logChannelId: z.string().optional(),
            autoTimeoutThreshold: z.number().optional()
        })
    }),
    trivia: z.object({
        entryFee: bigIntStringSchema,
        rewardMultiplier: z.number(),
        timeoutSeconds: z.number(),
        cooldownMs: z.number(),
        categories: z.array(z.number()).default([]),
        difficulty: z.enum(['easy', 'medium', 'hard', 'random']),
    }).optional(),
    system: z.record(z.string(), z.any()).optional(),
});

export type FormValues = z.infer<typeof formSchema>;

export interface ConfigMeta {
    roles: { id: string, name: string, color: string }[];
    channels: { id: string, name: string, type: number }[];
    commands: { name: string, category: string }[];
}

export const toSelectValue = (v: string | undefined | null) => v || NONE_VALUE;
export const fromSelectValue = (v: string) => v === NONE_VALUE ? "" : v;

export function useSettings() {
    const [meta, setMeta] = useState<ConfigMeta | null>(null);
    const [loading, setLoading] = useState(true);
    const [isSaving, setIsSaving] = useState(false);

    const form = useForm<FormValues>({
        resolver: zodResolver(formSchema) as any,
        defaultValues: {
            economy: {
                daily: { amount: "0", streakBonus: "0", weeklyBonus: "0", cooldownMs: 0 },
                transfers: { minAmount: "0", allowSelfTransfer: false },
                exam: { multMin: 1, multMax: 1 }
            },
            leveling: { base: 100, exponent: 1.5, chat: { minXp: 10, maxXp: 20, cooldownMs: 60000 } },
            inventory: { maxStackSize: "1", maxSlots: 10 },
            moderation: {
                prune: { maxAmount: 100, confirmThreshold: 50, batchSize: 100, batchDelayMs: 1000 },
                cases: { dmOnWarn: true }
            },
            lootdrop: {
                spawnChance: 0.05,
                minMessages: 10,
                cooldownMs: 300000,
                activityWindowMs: 600000,
                reward: { min: 100, max: 500, currency: "AU" }
            }
        }
    });

    const loadSettings = useCallback(async () => {
        setLoading(true);
        try {
            const [config, metaData] = await Promise.all([
                fetch("/api/settings").then(res => res.json()),
                fetch("/api/settings/meta").then(res => res.json())
            ]);
            form.reset(config as any);
            setMeta(metaData);
        } catch (err) {
            toast.error("Failed to load settings", {
                description: "Unable to fetch bot configuration. Please try again."
            });
            console.error(err);
        } finally {
            setLoading(false);
        }
    }, [form]);

    useEffect(() => {
        loadSettings();
    }, [loadSettings]);

    const saveSettings = async (data: FormValues) => {
        setIsSaving(true);
        try {
            const response = await fetch("/api/settings", {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify(data)
            });

            if (!response.ok) throw new Error("Failed to save");

            toast.success("Settings saved successfully", {
                description: "Bot configuration has been updated and reloaded."
            });
            // Reload settings to ensure we have the latest state
            await loadSettings();
        } catch (error) {
            toast.error("Failed to save settings", {
                description: error instanceof Error ? error.message : "Unable to save changes. Please try again."
            });
            console.error(error);
        } finally {
            setIsSaving(false);
        }
    };

    return {
        form,
        meta,
        loading,
        isSaving,
        saveSettings,
        loadSettings
    };
}
