import {
    disableTwoFactorSC,
    generateBackupCodesSQ,
    setupTwoFactorSC,
    verifyAndEnableTwoFactorSC,
} from "$lib/domains/security/twofa.remote";
import { toast } from "svelte-sonner";
import QRCode from "qrcode";

class TwoFactorViewModel {
    twoFactorEnabled = $state(false);
    twoFactorSetupInProgress = $state(false);
    showingBackupCodes = $state(false);
    qrCodeUrl = $state<string | null>(null);
    twoFactorSecret = $state<string | null>(null);
    backupCodes = $state<string[]>([]);
    twoFactorVerificationCode = $state("");
    isLoading = $state(false);
    errorMessage = $state<string | null>(null);

    async startTwoFactorSetup() {
        this.isLoading = true;
        this.errorMessage = null;

        try {
            const result = await setupTwoFactorSC({});
            if (result?.error || !result?.data?.totpURI) {
                this.errorMessage =
                    result?.error?.message || "Could not enable 2FA";
                toast.error(this.errorMessage, {
                    description:
                        result?.error?.description || "Please try again later",
                });
                return;
            }

            const qrCodeDataUrl = await QRCode.toDataURL(result.data.totpURI, {
                width: 256,
                margin: 2,
                color: { dark: "#000000", light: "#FFFFFF" },
            });

            this.qrCodeUrl = qrCodeDataUrl;
            this.twoFactorSetupInProgress = true;
            this.twoFactorSecret = result.data.secret;
            this.twoFactorVerificationCode = "";
            toast("Setup enabled");
        } catch (error) {
            this.errorMessage = "Could not enable 2FA";
            toast.error(this.errorMessage, {
                description:
                    error instanceof Error ? error.message : "Please try again later",
            });
        } finally {
            this.isLoading = false;
        }
    }

    async completeTwoFactorSetup() {
        if (!this.twoFactorVerificationCode) {
            this.errorMessage =
                "Please enter the verification code from your authenticator app.";
            return;
        }

        this.isLoading = true;
        this.errorMessage = null;

        try {
            const verifyResult = await verifyAndEnableTwoFactorSC({
                code: this.twoFactorVerificationCode,
            });

            if (verifyResult?.error) {
                this.errorMessage =
                    verifyResult.error.message || "Invalid verification code";
                toast.error(this.errorMessage, {
                    description:
                        verifyResult.error.description || "Please try again",
                });
                return;
            }

            const backupCodesResult = await generateBackupCodesSQ();
            if (backupCodesResult?.error || !Array.isArray(backupCodesResult?.data)) {
                toast.error("2FA enabled, but failed to generate backup codes", {
                    description: "You can generate them later in settings",
                });
            } else {
                this.backupCodes = backupCodesResult.data;
                this.showingBackupCodes = true;
            }

            this.twoFactorEnabled = true;
            this.twoFactorSetupInProgress = false;
            this.twoFactorVerificationCode = "";
            toast.success("Two-factor authentication enabled", {
                description: "Your account is now more secure",
            });
        } catch (error) {
            this.errorMessage = "Invalid verification code";
            toast.error(this.errorMessage, {
                description:
                    error instanceof Error ? error.message : "Please try again",
            });
        } finally {
            this.isLoading = false;
        }
    }

    async disableTwoFactor() {
        this.isLoading = true;
        this.errorMessage = null;

        try {
            const result = await disableTwoFactorSC({ code: "" });
            if (result?.error) {
                this.errorMessage = result.error.message || "Failed to disable 2FA";
                toast.error(this.errorMessage, {
                    description: result.error.description || "Please try again later",
                });
                return;
            }

            this.twoFactorEnabled = false;
            this.backupCodes = [];
            this.qrCodeUrl = null;
            this.showingBackupCodes = false;
            this.twoFactorSecret = null;
            toast.success("Two-factor authentication disabled");
        } catch (error) {
            this.errorMessage = "Failed to disable 2FA";
            toast.error(this.errorMessage, {
                description:
                    error instanceof Error ? error.message : "Please try again later",
            });
        } finally {
            this.isLoading = false;
        }
    }

    async generateNewBackupCodes() {
        this.isLoading = true;
        this.errorMessage = null;

        try {
            const result = await generateBackupCodesSQ();
            if (result?.error || !Array.isArray(result?.data)) {
                this.errorMessage =
                    result?.error?.message || "Failed to generate new backup codes";
                toast.error(this.errorMessage, {
                    description:
                        result?.error?.description || "Please try again later",
                });
                return;
            }

            this.backupCodes = result.data;
            this.showingBackupCodes = true;
            toast.success("New backup codes generated", {
                description: "Your previous backup codes are now invalid",
            });
        } catch (error) {
            this.errorMessage = "Failed to generate new backup codes";
            toast.error(this.errorMessage, {
                description:
                    error instanceof Error ? error.message : "Please try again later",
            });
        } finally {
            this.isLoading = false;
        }
    }

    copyAllBackupCodes() {
        const codesText = this.backupCodes.join("\n");
        navigator.clipboard.writeText(codesText);
        toast.success("All backup codes copied to clipboard");
    }

    downloadBackupCodes() {
        const codesText = this.backupCodes.join("\n");
        const blob = new Blob(
            [
                `Two-Factor Authentication Backup Codes\n\nGenerated: ${new Date().toLocaleString()}\n\n${codesText}\n\nKeep these codes in a safe place. Each code can only be used once.`,
            ],
            {
                type: "text/plain",
            },
        );

        const url = URL.createObjectURL(blob);
        const link = document.createElement("a");
        link.href = url;
        link.download = `2fa-backup-codes-${new Date().toISOString().split("T")[0]}.txt`;
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
        URL.revokeObjectURL(url);

        toast.success("Backup codes downloaded");
    }

    confirmBackupCodesSaved() {
        this.showingBackupCodes = false;
        toast.success("Great! Your backup codes are safely stored");
    }

    cancelSetup() {
        this.twoFactorSetupInProgress = false;
        this.twoFactorSecret = null;
        this.qrCodeUrl = null;
        this.twoFactorVerificationCode = "";
        this.errorMessage = null;
        this.showingBackupCodes = false;
    }

    copyToClipboard(text: string) {
        navigator.clipboard.writeText(text);
    }

    reset() {
        this.twoFactorEnabled = false;
        this.twoFactorSetupInProgress = false;
        this.showingBackupCodes = false;
        this.qrCodeUrl = null;
        this.backupCodes = [];
        this.twoFactorSecret = null;
        this.twoFactorVerificationCode = "";
        this.isLoading = false;
        this.errorMessage = null;
    }
}

export const twofactorVM = new TwoFactorViewModel();
