/**
 * Setup wizard page.
 *
 * Displayed automatically on first launch when no configuration exists.
 * Once submitted successfully the user is redirected to the login page.
 * All fields use Fluent UI v9 components and inline validation.
 */

import { useEffect, useState } from "react";
import {
  Button,
  Field,
  Input,
  makeStyles,
  MessageBar,
  MessageBarBody,
  Spinner,
  Text,
  tokens,
} from "@fluentui/react-components";
import { useNavigate } from "react-router-dom";
import type { ChangeEvent, FormEvent } from "react";
import { ApiError } from "../api/client";
import { getSetupStatus, submitSetup } from "../api/setup";

// ---------------------------------------------------------------------------
// Styles
// ---------------------------------------------------------------------------

const useStyles = makeStyles({
  root: {
    display: "flex",
    justifyContent: "center",
    alignItems: "flex-start",
    minHeight: "100vh",
    padding: `${tokens.spacingVerticalXXL} ${tokens.spacingHorizontalM}`,
    backgroundColor: tokens.colorNeutralBackground2,
  },
  card: {
    width: "100%",
    maxWidth: "480px",
    backgroundColor: tokens.colorNeutralBackground1,
    borderRadius: tokens.borderRadiusXLarge,
    padding: tokens.spacingVerticalXXL,
    boxShadow: tokens.shadow8,
  },
  heading: {
    marginBottom: tokens.spacingVerticalL,
    display: "block",
  },
  description: {
    marginBottom: tokens.spacingVerticalXXL,
    color: tokens.colorNeutralForeground2,
    display: "block",
  },
  fields: {
    display: "flex",
    flexDirection: "column",
    gap: tokens.spacingVerticalM,
  },
  submitRow: {
    marginTop: tokens.spacingVerticalL,
  },
  error: {
    marginBottom: tokens.spacingVerticalM,
  },
});

// ---------------------------------------------------------------------------
// Form state
// ---------------------------------------------------------------------------

interface FormValues {
  masterPassword: string;
  confirmPassword: string;
  databasePath: string;
  fail2banSocket: string;
  timezone: string;
  sessionDurationMinutes: string;
}

const DEFAULT_VALUES: FormValues = {
  masterPassword: "",
  confirmPassword: "",
  databasePath: "bangui.db",
  fail2banSocket: "/var/run/fail2ban/fail2ban.sock",
  timezone: "UTC",
  sessionDurationMinutes: "60",
};

// ---------------------------------------------------------------------------
// Component
// ---------------------------------------------------------------------------

/**
 * First-run setup wizard page.
 * Collects master password and server preferences.
 */
export function SetupPage(): React.JSX.Element {
  const styles = useStyles();
  const navigate = useNavigate();

  const [checking, setChecking] = useState(true);
  const [values, setValues] = useState<FormValues>(DEFAULT_VALUES);
  const [errors, setErrors] = useState<Partial<Record<keyof FormValues, string>>>({});
  const [apiError, setApiError] = useState<string | null>(null);
  const [submitting, setSubmitting] = useState(false);

  // Redirect to /login if setup has already been completed.
  // Show a full-screen spinner while the check is in flight to prevent
  // the form from flashing before the redirect fires.
  useEffect(() => {
    let cancelled = false;
    getSetupStatus()
      .then((res) => {
        if (!cancelled) {
          if (res.completed) {
            navigate("/login", { replace: true });
          } else {
            setChecking(false);
          }
        }
      })
      .catch(() => {
        // Failed check: the backend may still be starting up. Stay on this
        // page so the user can attempt setup once the backend is ready.
        console.warn("SetupPage: setup status check failed — rendering setup form");
        if (!cancelled) setChecking(false);
      });
    return (): void => {
      cancelled = true;
    };
  }, [navigate]);

  // ---------------------------------------------------------------------------
  // Handlers
  // ---------------------------------------------------------------------------

  function handleChange(field: keyof FormValues) {
    return (ev: ChangeEvent<HTMLInputElement>): void => {
      setValues((prev) => ({ ...prev, [field]: ev.target.value }));
      // Clear field-level error on change.
      setErrors((prev) => ({ ...prev, [field]: undefined }));
    };
  }

  function validate(): boolean {
    const next: Partial<Record<keyof FormValues, string>> = {};

    if (values.masterPassword.length < 8) {
      next.masterPassword = "Password must be at least 8 characters.";
    }
    if (values.masterPassword !== values.confirmPassword) {
      next.confirmPassword = "Passwords do not match.";
    }
    if (!values.databasePath.trim()) {
      next.databasePath = "Database path is required.";
    }
    if (!values.fail2banSocket.trim()) {
      next.fail2banSocket = "Socket path is required.";
    }
    const duration = parseInt(values.sessionDurationMinutes, 10);
    if (isNaN(duration) || duration < 1) {
      next.sessionDurationMinutes = "Session duration must be at least 1 minute.";
    }

    setErrors(next);
    return Object.keys(next).length === 0;
  }

  async function handleSubmit(ev: FormEvent<HTMLFormElement>): Promise<void> {
    ev.preventDefault();
    setApiError(null);

    if (!validate()) return;

    setSubmitting(true);
    try {
      await submitSetup({
        master_password: values.masterPassword,
        database_path: values.databasePath,
        fail2ban_socket: values.fail2banSocket,
        timezone: values.timezone,
        session_duration_minutes: parseInt(values.sessionDurationMinutes, 10),
      });
      navigate("/login", { replace: true });
    } catch (err) {
      if (err instanceof ApiError) {
        setApiError(err.message || `Error ${String(err.status)}`);
      } else {
        setApiError("An unexpected error occurred. Please try again.");
      }
    } finally {
      setSubmitting(false);
    }
  }

  // ---------------------------------------------------------------------------
  // Render
  // ---------------------------------------------------------------------------

  if (checking) {
    return (
      <div
        style={{
          display: "flex",
          justifyContent: "center",
          alignItems: "center",
          minHeight: "100vh",
        }}
      >
        <Spinner size="large" label="Loading…" />
      </div>
    );
  }

  return (
    <div className={styles.root}>
      <div className={styles.card}>
        <Text as="h1" size={700} weight="semibold" className={styles.heading}>
          BanGUI Setup
        </Text>
        <Text size={300} className={styles.description}>
          Configure BanGUI for first use. This page will not be shown again once setup
          is complete.
        </Text>

        {apiError !== null && (
          <MessageBar intent="error" className={styles.error}>
            <MessageBarBody>{apiError}</MessageBarBody>
          </MessageBar>
        )}

        <form onSubmit={(ev) => void handleSubmit(ev)}>
          {/* Hidden username field — required by accessibility guidelines for
              password managers to correctly identify the credential form. */}
          <input
            type="text"
            autoComplete="username"
            aria-hidden="true"
            tabIndex={-1}
            value="bangui"
            readOnly
            style={{ display: "none" }}
          />
          <div className={styles.fields}>
            <Field
              label="Master Password"
              required
              validationMessage={errors.masterPassword}
              validationState={errors.masterPassword ? "error" : "none"}
            >
              <Input
                type="password"
                value={values.masterPassword}
                onChange={handleChange("masterPassword")}
                autoComplete="new-password"
              />
            </Field>

            <Field
              label="Confirm Password"
              required
              validationMessage={errors.confirmPassword}
              validationState={errors.confirmPassword ? "error" : "none"}
            >
              <Input
                type="password"
                value={values.confirmPassword}
                onChange={handleChange("confirmPassword")}
                autoComplete="new-password"
              />
            </Field>

            <Field
              label="Database Path"
              hint="Path where BanGUI stores its SQLite database."
              validationMessage={errors.databasePath}
              validationState={errors.databasePath ? "error" : "none"}
            >
              <Input
                value={values.databasePath}
                onChange={handleChange("databasePath")}
              />
            </Field>

            <Field
              label="fail2ban Socket Path"
              hint="Unix socket used to communicate with the fail2ban daemon."
              validationMessage={errors.fail2banSocket}
              validationState={errors.fail2banSocket ? "error" : "none"}
            >
              <Input
                value={values.fail2banSocket}
                onChange={handleChange("fail2banSocket")}
              />
            </Field>

            <Field
              label="Timezone"
              hint="IANA timezone identifier (e.g. UTC, Europe/Berlin)."
            >
              <Input
                value={values.timezone}
                onChange={handleChange("timezone")}
              />
            </Field>

            <Field
              label="Session Duration (minutes)"
              hint="How long a login session stays active."
              validationMessage={errors.sessionDurationMinutes}
              validationState={errors.sessionDurationMinutes ? "error" : "none"}
            >
              <Input
                type="number"
                value={values.sessionDurationMinutes}
                onChange={handleChange("sessionDurationMinutes")}
                min={1}
              />
            </Field>
          </div>

          <div className={styles.submitRow}>
            <Button
              type="submit"
              appearance="primary"
              disabled={submitting}
              icon={submitting ? <Spinner size="tiny" /> : undefined}
            >
              {submitting ? "Saving…" : "Complete Setup"}
            </Button>
          </div>
        </form>
      </div>
    </div>
  );
}
