import React, { useState, useRef, useEffect, type FormEvent } from "react";
import Button from "@mui/joy/Button";
import { toast } from "react-toastify";
import { API_URL } from "@/config";

function getCookie(name: string): string | null {
    const value = `; ${document.cookie}`;
    const parts = value.split(`; ${name}=`);
    if (parts.length === 2) return decodeURIComponent(parts.pop()!.split(';').shift()!);
    return null;
}

function clearCookie(name: string): void {
    document.cookie = `${name}=; Max-Age=0; path=/;`;
}

// Trusted domains for redirect validation
const TRUSTED_DOMAINS = ['codey.horse', 'boatson.boats'];

/**
 * Parse and decode the redirect URL from query params
 */
function getRedirectParam(): string | null {
    const urlParams = new URLSearchParams(window.location.search);
    let redirectParam = urlParams.get('redirect') || urlParams.get('returnUrl');
    
    if (!redirectParam) return null;
    
    // Handle double-encoding
    if (redirectParam.includes('%')) {
        try {
            redirectParam = decodeURIComponent(redirectParam);
        } catch {
            // If decoding fails, use the original value
        }
    }
    return redirectParam;
}

/**
 * Check if a URL is a valid trusted external URL
 */
function isTrustedExternalUrl(url: string): boolean {
    try {
        const parsed = new URL(url);
        if (parsed.protocol !== 'https:') return false;
        return TRUSTED_DOMAINS.some(domain => 
            parsed.hostname === domain || parsed.hostname.endsWith('.' + domain)
        );
    } catch {
        return false;
    }
}

/**
 * Get validated redirect URL for POST-LOGIN redirect (after form submission)
 * Allows: relative paths OR trusted external URLs
 * This is safe because the user just authenticated fresh
 */
function getPostLoginRedirectUrl(): string {
    const redirectParam = getRedirectParam();
    if (!redirectParam) return '/';
    
    // Relative path: must start with '/' but not '//' (protocol-relative)
    if (redirectParam.startsWith('/') && !redirectParam.startsWith('//')) {
        return redirectParam;
    }
    
    // External URL: must be https and trusted domain
    if (isTrustedExternalUrl(redirectParam)) {
        return redirectParam;
    }
    
    return '/';
}

/**
 * Get validated redirect URL for AUTO-REDIRECT (when already logged in)
 * Only allows: relative paths
 * External URLs are BLOCKED because if a logged-in user was redirected here
 * from an external resource, nginx denied them access - redirecting back would loop
 */
function getAutoRedirectUrl(): string | null {
    const redirectParam = getRedirectParam();
    if (!redirectParam) return null;
    
    // Only allow relative paths for auto-redirect
    if (redirectParam.startsWith('/') && !redirectParam.startsWith('//')) {
        return redirectParam;
    }
    
    // Block external URLs - would cause redirect loop with nginx
    return null;
}

/**
 * Check if the returnUrl is an external trusted domain
 * Used to detect access denial from nginx-protected external vhosts
 */
function isExternalReturnUrl(): boolean {
    const redirectParam = getRedirectParam();
    if (!redirectParam) return false;
    if (redirectParam.startsWith('/')) return false;
    return isTrustedExternalUrl(redirectParam);
}

interface LoginPageProps {
    loggedIn?: boolean;
    accessDenied?: boolean;
    requiredRoles?: string[] | string;
}

export default function LoginPage({ loggedIn = false, accessDenied = false, requiredRoles = [] }: LoginPageProps): React.ReactElement {
    const [username, setUsername] = useState<string>("");
    const [password, setPassword] = useState<string>("");
    const [loading, setLoading] = useState<boolean>(false);

    const passwordRef = useRef<HTMLInputElement>(null);

    useEffect(() => {
        if (passwordRef.current && password === "") {
            passwordRef.current.value = "";
        }
    }, []);

    // If user is already logged in and not access denied, redirect them
    // This handles the case where token was refreshed successfully
    // NOTE: Only auto-redirect to relative URLs - external URLs mean nginx denied access
    useEffect(() => {
        if (loggedIn && !accessDenied) {
            const returnTo = getAutoRedirectUrl() || '/';
            window.location.href = returnTo;
        }
    }, [loggedIn, accessDenied]);

    async function handleSubmit(e: FormEvent<HTMLFormElement>): Promise<void> {
        e.preventDefault();
        setLoading(true);

        try {
            if (!username || !password) {
                setLoading(false);
                if (!toast.isActive("login-missing-data-toast")) {
                    toast.error("Username and password are required", {
                        toastId: "login-missing-data-toast",
                    });
                }
                return;
            }

            const formData = new URLSearchParams({
                username,
                password,
                grant_type: "password",
                scope: "",
                client_id: "b8308cf47d424e66",
                client_secret: "",
            });

            const resp = await fetch(`${API_URL}/auth/login`, {
                method: "POST",
                headers: { "Content-Type": "application/x-www-form-urlencoded" },
                credentials: "include",
                body: formData.toString(),
            });

            if (resp.status === 401) {
                toast.error("Invalid username or password", {
                    toastId: "login-error-invalid-toast",
                });
                setLoading(false);
                return;
            }

            if (!resp.ok) {
                const data = await resp.json().catch(() => ({}));
                toast.error(data.detail ? `Login failed: ${data.detail}` : "Login failed", {
                    toastId: "login-error-failed-toast",
                });
                setLoading(false);
                return;
            }

            const data = await resp.json();
            if (data.access_token) {
                toast.success("Login successful!", {
                    toastId: "login-success-toast",
                });
                // After fresh login, allow redirect to external trusted URLs
                const returnTo = getPostLoginRedirectUrl();
                window.location.href = returnTo;
            } else {
                toast.error("Login failed: no access token received", {
                    toastId: "login-error-no-token-toast",
                });
                setLoading(false);
            }
        } catch (error) {
            toast.error("Network error during login", {
                toastId: "login-error-network-toast",
            });
            console.error("Login error:", error);
            setLoading(false);
        }
    }

    if (loggedIn) {
        const rolesList = Array.isArray(requiredRoles) ? requiredRoles : (requiredRoles ? requiredRoles.split(',') : []);
        // Check if this is an external resource denial (nginx redirect)
        const isExternalDenial = rolesList.some(r => r === '(external resource)');
        const displayRoles = rolesList.filter(r => r !== '(external resource)');
        
        return (
            <div className="flex items-center justify-center px-4 py-16">
                <div className="max-w-md w-full bg-white dark:bg-[#1a1a1a] rounded-2xl shadow-xl shadow-neutral-900/5 dark:shadow-black/30 border border-neutral-200/60 dark:border-neutral-800/60 px-10 py-8 text-center">
                    <img className="logo-auth mx-auto mb-5" src="/images/zim.png" alt="Logo" />
                    <h2 className="text-2xl font-bold text-neutral-900 dark:text-white mb-3 tracking-tight">Access Denied</h2>
                    <p className="text-sm text-neutral-600 dark:text-neutral-400 mb-4">
                        You don't have permission to access this resource.
                    </p>
                    {displayRoles.length > 0 && (
                        <div className="mb-5 p-3 bg-neutral-100 dark:bg-neutral-800/50 rounded-xl border border-neutral-200/60 dark:border-neutral-700/60">
                            <p className="text-sm text-neutral-500 dark:text-neutral-500 mb-2 font-medium">Required role{displayRoles.length > 1 ? 's' : ''}:</p>
                            <div className="flex flex-wrap justify-center gap-2">
                                {displayRoles.map((role, i) => (
                                    <span key={i} className="px-2.5 py-1 text-xs font-semibold bg-red-100 dark:bg-red-900/40 text-red-700 dark:text-red-300 rounded-full">
                                        {role}
                                    </span>
                                ))}
                            </div>
                        </div>
                    )}
                    {isExternalDenial && displayRoles.length === 0 && (
                        <div className="mb-5 p-3 bg-amber-50 dark:bg-amber-900/20 rounded-xl border border-amber-200/60 dark:border-amber-700/40">
                            <p className="text-sm text-amber-700 dark:text-amber-300">
                                This resource requires elevated permissions.
                            </p>
                        </div>
                    )}
                    <p className="text-xs italic text-neutral-400 dark:text-neutral-500 mb-5">
                        If you believe this is an error, scream at codey.
                    </p>
                    <Button
                        className="w-full py-2.5 px-6 bg-neutral-900 dark:bg-white text-white dark:text-neutral-900 font-semibold rounded-xl hover:bg-neutral-800 dark:hover:bg-neutral-100 transition-colors shadow-sm"
                        color="primary"
                        variant="solid"
                        onClick={() => (window.location.href = "/")}
                    >
                        Go Home
                    </Button>
                </div>
            </div>
        );
    }

    return (
        <div className="flex items-center justify-center px-4 py-16">
            <div className="max-w-md w-full bg-white dark:bg-[#1a1a1a] rounded-2xl shadow-xl shadow-neutral-900/5 dark:shadow-black/30 border border-neutral-200/60 dark:border-neutral-800/60 px-10 py-8">
                <div className="text-center mb-8">
                    <img className="logo-auth mx-auto mb-4" src="/images/zim.png" alt="Logo" />
                    <h2 className="text-2xl font-bold text-neutral-900 dark:text-white tracking-tight">
                        Log In
                    </h2>
                    <p className="text-sm text-neutral-500 dark:text-neutral-400 mt-1">
                        Sign in to continue
                    </p>
                </div>

                <form className="space-y-5" onSubmit={handleSubmit} noValidate>
                    <div className="space-y-2">
                        <label htmlFor="username" className="block text-sm font-medium text-neutral-700 dark:text-neutral-300">
                            Username
                        </label>
                        <input
                            type="text"
                            id="username"
                            name="username"
                            autoComplete="off"
                            value={username}
                            onChange={(e) => setUsername(e.target.value)}
                            required
                            disabled={loading}
                            className="w-full border border-neutral-200 dark:border-neutral-700 rounded-xl px-4 py-3 bg-white dark:bg-neutral-900/50 text-neutral-900 dark:text-white focus:border-blue-500 dark:focus:border-blue-400 focus:ring-2 focus:ring-blue-500/20 transition-all outline-none"
                            placeholder="Enter your username"
                        />
                    </div>

                    <div className="space-y-2">
                        <label htmlFor="password" className="block text-sm font-medium text-neutral-700 dark:text-neutral-300">
                            Password
                        </label>
                        <input
                            type="password"
                            id="password"
                            name="password"
                            autoComplete="new-password"
                            spellCheck="false"
                            ref={passwordRef}
                            value={password}
                            onChange={(e) => setPassword(e.target.value)}
                            required
                            disabled={loading}
                            className="w-full border border-neutral-200 dark:border-neutral-700 rounded-xl px-4 py-3 bg-white dark:bg-neutral-900/50 text-neutral-900 dark:text-white focus:border-blue-500 dark:focus:border-blue-400 focus:ring-2 focus:ring-blue-500/20 transition-all outline-none"
                            placeholder="Enter your password"
                        />
                    </div>

                    <div className="pt-2">
                        <button
                            type="submit"
                            disabled={loading}
                            className={`w-full py-3 px-6 bg-blue-600 hover:bg-blue-700 focus:ring-4 focus:ring-blue-500/30 text-white rounded-xl font-semibold shadow-sm transition-all ${loading ? "opacity-60 cursor-not-allowed" : ""}`}
                        >
                            {loading ? "Signing In..." : "Sign In"}
                        </button>
                    </div>
                </form>
            </div>
        </div>
    );
}
