import React, {useState, useEffect} from "react";
import {cn} from "@/lib/utils";
import {Button} from "@/components/ui/button";
import {Input} from "@/components/ui/input";
import {Label} from "@/components/ui/label";
import {Alert, AlertTitle, AlertDescription} from "@/components/ui/alert";
import {Separator} from "@/components/ui/separator";
import axios from "axios";

function setCookie(name: string, value: string, days = 7) {
    const expires = new Date(Date.now() + days * 864e5).toUTCString();
    document.cookie = `${name}=${encodeURIComponent(value)}; expires=${expires}; path=/`;
}

function getCookie(name: string) {
    return document.cookie.split('; ').reduce((r, v) => {
        const parts = v.split('=');
        return parts[0] === name ? decodeURIComponent(parts[1]) : r;
    }, "");
}

const apiBase = import.meta.env.DEV ? "http://localhost:8081/users" : "/users";

const API = axios.create({
    baseURL: apiBase,
});

interface HomepageAuthProps extends React.ComponentProps<"div"> {
    setLoggedIn: (loggedIn: boolean) => void;
    setIsAdmin: (isAdmin: boolean) => void;
    setUsername: (username: string | null) => void;
    setUserId: (userId: string | null) => void;
    loggedIn: boolean;
    authLoading: boolean;
    dbError: string | null;
    setDbError: (error: string | null) => void;
}

export function HomepageAuth({
                                 className,
                                 setLoggedIn,
                                 setIsAdmin,
                                 setUsername,
                                 setUserId,
                                 loggedIn,
                                 authLoading,
                                 dbError,
                                 setDbError,
                                 ...props
                             }: HomepageAuthProps) {
    const [tab, setTab] = useState<"login" | "signup" | "external" | "reset">("login");
    const [localUsername, setLocalUsername] = useState("");
    const [password, setPassword] = useState("");
    const [signupConfirmPassword, setSignupConfirmPassword] = useState("");
    const [loading, setLoading] = useState(false);
    const [oidcLoading, setOidcLoading] = useState(false);
    const [error, setError] = useState<string | null>(null);
    const [internalLoggedIn, setInternalLoggedIn] = useState(false);
    const [firstUser, setFirstUser] = useState(false);
    const [registrationAllowed, setRegistrationAllowed] = useState(true);
    const [oidcConfigured, setOidcConfigured] = useState(false);

    const [resetStep, setResetStep] = useState<"initiate" | "verify" | "newPassword">("initiate");
    const [resetCode, setResetCode] = useState("");
    const [newPassword, setNewPassword] = useState("");
    const [confirmPassword, setConfirmPassword] = useState("");
    const [tempToken, setTempToken] = useState("");
    const [resetLoading, setResetLoading] = useState(false);
    const [resetSuccess, setResetSuccess] = useState(false);

    useEffect(() => {
        setInternalLoggedIn(loggedIn);
    }, [loggedIn]);

    useEffect(() => {
        API.get("/registration-allowed").then(res => {
            setRegistrationAllowed(res.data.allowed);
        });
    }, []);

    useEffect(() => {
        API.get("/oidc-config").then((response) => {
            if (response.data) {
                setOidcConfigured(true);
            } else {
                setOidcConfigured(false);
            }
        }).catch((error) => {
            if (error.response?.status === 404) {
                setOidcConfigured(false);
            } else {
                setOidcConfigured(false);
            }
        });
    }, []);

    useEffect(() => {
        API.get("/count").then(res => {
            if (res.data.count === 0) {
                setFirstUser(true);
                setTab("signup");
            } else {
                setFirstUser(false);
            }
            setDbError(null);
        }).catch(() => {
            setDbError("Could not connect to the database. Please try again later.");
        });
    }, [setDbError]);

    async function handleSubmit(e: React.FormEvent) {
        e.preventDefault();
        setError(null);
        setLoading(true);

        if (!localUsername.trim()) {
            setError("Username is required");
            setLoading(false);
            return;
        }

        try {
            let res, meRes;
            if (tab === "login") {
                res = await API.post("/login", {username: localUsername, password});
            } else {
                if (password !== signupConfirmPassword) {
                    setError("Passwords do not match");
                    setLoading(false);
                    return;
                }
                if (password.length < 6) {
                    setError("Password must be at least 6 characters long");
                    setLoading(false);
                    return;
                }
                await API.post("/create", {username: localUsername, password});
                res = await API.post("/login", {username: localUsername, password});
            }
            setCookie("jwt", res.data.token);
            [meRes] = await Promise.all([
                API.get("/me", {headers: {Authorization: `Bearer ${res.data.token}`}}),
                API.get("/db-health")
            ]);
            setInternalLoggedIn(true);
            setLoggedIn(true);
            setIsAdmin(!!meRes.data.is_admin);
            setUsername(meRes.data.username || null);
            setUserId(meRes.data.id || null);
            setDbError(null);
            if (tab === "signup") {
                setSignupConfirmPassword("");
            }
        } catch (err: any) {
            setError(err?.response?.data?.error || "Unknown error");
            setInternalLoggedIn(false);
            setLoggedIn(false);
            setIsAdmin(false);
            setUsername(null);
            setUserId(null);
            setCookie("jwt", "", -1);
            if (err?.response?.data?.error?.includes("Database")) {
                setDbError("Could not connect to the database. Please try again later.");
            } else {
                setDbError(null);
            }
        } finally {
            setLoading(false);
        }
    }

    async function initiatePasswordReset() {
        setError(null);
        setResetLoading(true);
        try {
            await API.post("/initiate-reset", {username: localUsername});
            setResetStep("verify");
            setError(null);
        } catch (err: any) {
            setError(err?.response?.data?.error || "Failed to initiate password reset");
        } finally {
            setResetLoading(false);
        }
    }

    async function verifyResetCode() {
        setError(null);
        setResetLoading(true);
        try {
            const response = await API.post("/verify-reset-code", {
                username: localUsername,
                resetCode: resetCode
            });
            setTempToken(response.data.tempToken);
            setResetStep("newPassword");
            setError(null);
        } catch (err: any) {
            setError(err?.response?.data?.error || "Failed to verify reset code");
        } finally {
            setResetLoading(false);
        }
    }

    async function completePasswordReset() {
        setError(null);
        setResetLoading(true);

        if (newPassword !== confirmPassword) {
            setError("Passwords do not match");
            setResetLoading(false);
            return;
        }

        if (newPassword.length < 6) {
            setError("Password must be at least 6 characters long");
            setResetLoading(false);
            return;
        }

        try {
            await API.post("/complete-reset", {
                username: localUsername,
                tempToken: tempToken,
                newPassword: newPassword
            });

            setResetStep("initiate");
            setResetCode("");
            setNewPassword("");
            setConfirmPassword("");
            setTempToken("");
            setError(null);

            setResetSuccess(true);
        } catch (err: any) {
            setError(err?.response?.data?.error || "Failed to complete password reset");
        } finally {
            setResetLoading(false);
        }
    }

    function resetPasswordState() {
        setResetStep("initiate");
        setResetCode("");
        setNewPassword("");
        setConfirmPassword("");
        setTempToken("");
        setError(null);
        setResetSuccess(false);
        setSignupConfirmPassword("");
    }

    function clearFormFields() {
        setPassword("");
        setSignupConfirmPassword("");
        setError(null);
    }

    async function resetPassword() {

    }

    async function handleOIDCLogin() {
        setError(null);
        setOidcLoading(true);
        try {
            const authResponse = await API.get("/oidc/authorize");
            const {auth_url: authUrl} = authResponse.data;

            if (!authUrl || authUrl === 'undefined') {
                throw new Error('Invalid authorization URL received from backend');
            }

            window.location.replace(authUrl);
        } catch (err: any) {
            setError(err?.response?.data?.error || err?.message || "Failed to start OIDC login");
            setOidcLoading(false);
        }
    }

    useEffect(() => {
        const urlParams = new URLSearchParams(window.location.search);
        const success = urlParams.get('success');
        const token = urlParams.get('token');
        const error = urlParams.get('error');

        if (error) {
            setError(`OIDC authentication failed: ${error}`);
            setOidcLoading(false);
            window.history.replaceState({}, document.title, window.location.pathname);
            return;
        }

        if (success && token) {
            setOidcLoading(true);
            setError(null);

            setCookie("jwt", token);
            API.get("/me", {headers: {Authorization: `Bearer ${token}`}})
                .then(meRes => {
                    setInternalLoggedIn(true);
                    setLoggedIn(true);
                    setIsAdmin(!!meRes.data.is_admin);
                    setUsername(meRes.data.username || null);
                    setUserId(meRes.data.id || null);
                    setDbError(null);
                    window.history.replaceState({}, document.title, window.location.pathname);
                })
                .catch(err => {
                    setError("Failed to get user info after OIDC login");
                    setInternalLoggedIn(false);
                    setLoggedIn(false);
                    setIsAdmin(false);
                    setUsername(null);
                    setUserId(null);
                    setCookie("jwt", "", -1);
                    window.history.replaceState({}, document.title, window.location.pathname);
                })
                .finally(() => {
                    setOidcLoading(false);
                });
        }
    }, []);

    const Spinner = (
        <svg className="animate-spin mr-2 h-4 w-4 text-white inline-block" viewBox="0 0 24 24">
            <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" fill="none"/>
            <path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z"/>
        </svg>
    );

    return (
        <div
            className={cn(
                className
            )}
            {...props}
        >
            <div
                className={`w-[420px] max-w-full bg-background rounded-xl shadow-lg p-6 flex flex-col ${internalLoggedIn ? '' : 'border border-border'}`}>
                {dbError && (
                    <Alert variant="destructive" className="mb-4">
                        <AlertTitle>Error</AlertTitle>
                        <AlertDescription>{dbError}</AlertDescription>
                    </Alert>
                )}
                {firstUser && !dbError && !internalLoggedIn && (
                    <Alert variant="default" className="mb-4">
                        <AlertTitle>First User</AlertTitle>
                        <AlertDescription className="inline">
                            You are the first user and will be made an admin. You can view admin settings in the sidebar
                            user dropdown. If you think this is a mistake, check the docker logs, or create a{" "}
                            <a
                                href="https://github.com/LukeGus/Termix/issues/new"
                                target="_blank"
                                rel="noopener noreferrer"
                                className="text-blue-600 underline hover:text-blue-800 inline"
                            >
                                GitHub issue
                            </a>.
                        </AlertDescription>
                    </Alert>
                )}
                {!registrationAllowed && !internalLoggedIn && (
                    <Alert variant="destructive" className="mb-4">
                        <AlertTitle>Registration Disabled</AlertTitle>
                        <AlertDescription>
                            New account registration is currently disabled by an admin. Please log in or contact an
                            administrator.
                        </AlertDescription>
                    </Alert>
                )}
                {(internalLoggedIn || (authLoading && getCookie("jwt"))) && (
                    <div className="flex flex-col items-center gap-4">
                        <Alert className="my-2">
                            <AlertTitle>Logged in!</AlertTitle>
                            <AlertDescription>
                                You are logged in! Use the sidebar to access all available tools. To get started,
                                create an SSH Host in the SSH Manager tab. Once created, you can connect to that
                                host using the other apps in the sidebar.
                            </AlertDescription>
                        </Alert>

                        <div className="flex flex-row items-center gap-2">
                            <Button
                                variant="link"
                                className="text-sm"
                                onClick={() => window.open('https://github.com/LukeGus/Termix', '_blank')}
                            >
                                GitHub
                            </Button>
                            <div className="w-px h-4 bg-border"></div>
                            <Button
                                variant="link"
                                className="text-sm"
                                onClick={() => window.open('https://github.com/LukeGus/Termix/issues/new', '_blank')}
                            >
                                Feedback
                            </Button>
                            <div className="w-px h-4 bg-border"></div>
                            <Button
                                variant="link"
                                className="text-sm"
                                onClick={() => window.open('https://discord.com/invite/jVQGdvHDrf', '_blank')}
                            >
                                Discord
                            </Button>
                            <div className="w-px h-4 bg-border"></div>
                            <Button
                                variant="link"
                                className="text-sm"
                                onClick={() => window.open('https://github.com/sponsors/LukeGus', '_blank')}
                            >
                                Fund
                            </Button>
                        </div>
                    </div>
                )}
                {(!internalLoggedIn && (!authLoading || !getCookie("jwt"))) && (
                    <>
                        <div className="flex gap-2 mb-6">
                            <button
                                type="button"
                                className={cn(
                                    "flex-1 py-2 text-base font-medium rounded-md transition-all",
                                    tab === "login"
                                        ? "bg-primary text-primary-foreground shadow"
                                        : "bg-muted text-muted-foreground hover:bg-accent"
                                )}
                                onClick={() => {
                                    setTab("login");
                                    if (tab === "reset") resetPasswordState();
                                    if (tab === "signup") clearFormFields();
                                }}
                                aria-selected={tab === "login"}
                                disabled={loading || firstUser}
                            >
                                Login
                            </button>
                            <button
                                type="button"
                                className={cn(
                                    "flex-1 py-2 text-base font-medium rounded-md transition-all",
                                    tab === "signup"
                                        ? "bg-primary text-primary-foreground shadow"
                                        : "bg-muted text-muted-foreground hover:bg-accent"
                                )}
                                onClick={() => {
                                    setTab("signup");
                                    if (tab === "reset") resetPasswordState();
                                    if (tab === "login") clearFormFields();
                                }}
                                aria-selected={tab === "signup"}
                                disabled={loading || !registrationAllowed}
                            >
                                Sign Up
                            </button>
                            {oidcConfigured && (
                                <button
                                    type="button"
                                    className={cn(
                                        "flex-1 py-2 text-base font-medium rounded-md transition-all",
                                        tab === "external"
                                            ? "bg-primary text-primary-foreground shadow"
                                            : "bg-muted text-muted-foreground hover:bg-accent"
                                    )}
                                    onClick={() => {
                                        setTab("external");
                                        if (tab === "reset") resetPasswordState();
                                        if (tab === "login" || tab === "signup") clearFormFields();
                                    }}
                                    aria-selected={tab === "external"}
                                    disabled={oidcLoading}
                                >
                                    External
                                </button>
                            )}
                        </div>
                        <div className="mb-6 text-center">
                            <h2 className="text-xl font-bold mb-1">
                                {tab === "login" ? "Login to your account" :
                                    tab === "signup" ? "Create a new account" :
                                        tab === "external" ? "Login with external provider" :
                                            "Reset your password"}
                            </h2>
                        </div>

                        {tab === "external" || tab === "reset" ? (
                            <div className="flex flex-col gap-5">
                                {tab === "external" && (
                                    <>
                                        <div className="text-center text-muted-foreground mb-4">
                                            <p>Login using your configured external identity provider</p>
                                        </div>
                                        <Button
                                            type="button"
                                            className="w-full h-11 mt-2 text-base font-semibold"
                                            disabled={oidcLoading}
                                            onClick={handleOIDCLogin}
                                        >
                                            {oidcLoading ? Spinner : "Login with External Provider"}
                                        </Button>
                                    </>
                                )}
                                {tab === "reset" && (
                                    <>
                                        {resetStep === "initiate" && (
                                            <>
                                                <div className="text-center text-muted-foreground mb-4">
                                                    <p>Enter your username to receive a password reset code. The code
                                                        will be logged in the docker container logs.</p>
                                                </div>
                                                <div className="flex flex-col gap-4">
                                                    <div className="flex flex-col gap-2">
                                                        <Label htmlFor="reset-username">Username</Label>
                                                        <Input
                                                            id="reset-username"
                                                            type="text"
                                                            required
                                                            className="h-11 text-base"
                                                            value={localUsername}
                                                            onChange={e => setLocalUsername(e.target.value)}
                                                            disabled={resetLoading}
                                                        />
                                                    </div>
                                                    <Button
                                                        type="button"
                                                        className="w-full h-11 text-base font-semibold"
                                                        disabled={resetLoading || !localUsername.trim()}
                                                        onClick={initiatePasswordReset}
                                                    >
                                                        {resetLoading ? Spinner : "Send Reset Code"}
                                                    </Button>
                                                </div>
                                            </>
                                        )}

                                        {resetStep === "verify" && (
                                            <>
                                                <div className="text-center text-muted-foreground mb-4">
                                                    <p>Enter the 6-digit code from the docker container logs for
                                                        user: <strong>{localUsername}</strong></p>
                                                </div>
                                                <div className="flex flex-col gap-4">
                                                    <div className="flex flex-col gap-2">
                                                        <Label htmlFor="reset-code">Reset Code</Label>
                                                        <Input
                                                            id="reset-code"
                                                            type="text"
                                                            required
                                                            maxLength={6}
                                                            className="h-11 text-base text-center text-lg tracking-widest"
                                                            value={resetCode}
                                                            onChange={e => setResetCode(e.target.value.replace(/\D/g, ''))}
                                                            disabled={resetLoading}
                                                            placeholder="000000"
                                                        />
                                                    </div>
                                                    <Button
                                                        type="button"
                                                        className="w-full h-11 text-base font-semibold"
                                                        disabled={resetLoading || resetCode.length !== 6}
                                                        onClick={verifyResetCode}
                                                    >
                                                        {resetLoading ? Spinner : "Verify Code"}
                                                    </Button>
                                                    <Button
                                                        type="button"
                                                        variant="outline"
                                                        className="w-full h-11 text-base font-semibold"
                                                        disabled={resetLoading}
                                                        onClick={() => {
                                                            setResetStep("initiate");
                                                            setResetCode("");
                                                        }}
                                                    >
                                                        Back
                                                    </Button>
                                                </div>
                                            </>
                                        )}

                                        {resetSuccess && (
                                            <>
                                                <Alert className="mb-4">
                                                    <AlertTitle>Success!</AlertTitle>
                                                    <AlertDescription>
                                                        Your password has been successfully reset! You can now log in
                                                        with your new password.
                                                    </AlertDescription>
                                                </Alert>
                                                <Button
                                                    type="button"
                                                    className="w-full h-11 text-base font-semibold"
                                                    onClick={() => {
                                                        setTab("login");
                                                        resetPasswordState();
                                                    }}
                                                >
                                                    Go to Login
                                                </Button>
                                            </>
                                        )}

                                        {resetStep === "newPassword" && !resetSuccess && (
                                            <>
                                                <div className="text-center text-muted-foreground mb-4">
                                                    <p>Enter your new password for
                                                        user: <strong>{localUsername}</strong></p>
                                                </div>
                                                <div className="flex flex-col gap-4">
                                                    <div className="flex flex-col gap-2">
                                                        <Label htmlFor="new-password">New Password</Label>
                                                        <Input
                                                            id="new-password"
                                                            type="password"
                                                            required
                                                            className="h-11 text-base"
                                                            value={newPassword}
                                                            onChange={e => setNewPassword(e.target.value)}
                                                            disabled={resetLoading}
                                                        />
                                                    </div>
                                                    <div className="flex flex-col gap-2">
                                                        <Label htmlFor="confirm-password">Confirm Password</Label>
                                                        <Input
                                                            id="confirm-password"
                                                            type="password"
                                                            required
                                                            className="h-11 text-base"
                                                            value={confirmPassword}
                                                            onChange={e => setConfirmPassword(e.target.value)}
                                                            disabled={resetLoading}
                                                        />
                                                    </div>
                                                    <Button
                                                        type="button"
                                                        className="w-full h-11 text-base font-semibold"
                                                        disabled={resetLoading || !newPassword || !confirmPassword}
                                                        onClick={completePasswordReset}
                                                    >
                                                        {resetLoading ? Spinner : "Reset Password"}
                                                    </Button>
                                                    <Button
                                                        type="button"
                                                        variant="outline"
                                                        className="w-full h-11 text-base font-semibold"
                                                        disabled={resetLoading}
                                                        onClick={() => {
                                                            setResetStep("verify");
                                                            setNewPassword("");
                                                            setConfirmPassword("");
                                                        }}
                                                    >
                                                        Back
                                                    </Button>
                                                </div>
                                            </>
                                        )}
                                    </>
                                )}
                            </div>
                        ) : (
                            <form className="flex flex-col gap-5" onSubmit={handleSubmit}>
                                <div className="flex flex-col gap-2">
                                    <Label htmlFor="username">Username</Label>
                                    <Input
                                        id="username"
                                        type="text"
                                        required
                                        className="h-11 text-base"
                                        value={localUsername}
                                        onChange={e => setLocalUsername(e.target.value)}
                                        disabled={loading || internalLoggedIn}
                                    />
                                </div>
                                <div className="flex flex-col gap-2">
                                    <Label htmlFor="password">Password</Label>
                                    <Input id="password" type="password" required className="h-11 text-base"
                                           value={password} onChange={e => setPassword(e.target.value)}
                                           disabled={loading || internalLoggedIn}/>
                                </div>
                                {tab === "signup" && (
                                    <div className="flex flex-col gap-2">
                                        <Label htmlFor="signup-confirm-password">Confirm Password</Label>
                                        <Input id="signup-confirm-password" type="password" required
                                               className="h-11 text-base"
                                               value={signupConfirmPassword}
                                               onChange={e => setSignupConfirmPassword(e.target.value)}
                                               disabled={loading || internalLoggedIn}/>
                                    </div>
                                )}
                                <Button type="submit" className="w-full h-11 mt-2 text-base font-semibold"
                                        disabled={loading || internalLoggedIn}>
                                    {loading ? Spinner : (tab === "login" ? "Login" : "Sign Up")}
                                </Button>
                                {tab === "login" && (
                                    <Button type="button" variant="outline"
                                            className="w-full h-11 text-base font-semibold"
                                            disabled={loading || internalLoggedIn}
                                            onClick={() => {
                                                setTab("reset");
                                                resetPasswordState();
                                                clearFormFields();
                                            }}
                                    >
                                        Reset Password
                                    </Button>
                                )}
                            </form>
                        )}
                    </>
                )}
                {error && (
                    <Alert variant="destructive" className="mt-4">
                        <AlertTitle>Error</AlertTitle>
                        <AlertDescription>{error}</AlertDescription>
                    </Alert>
                )}
            </div>
        </div>
    );
}