import { useEffect, useState } from 'react'
import {
  beginSetupTOTP,
  completeSetup,
  DEFAULT_NETWORK_SETTINGS,
  DEFAULT_SECURITY_SETTINGS,
  previewNetworkAccess,
  type AccessMode,
  type NetworkSettings,
  type SecuritySettings,
  verifySetupTOTP,
} from './api/client'
import {
  validateHostname,
  validateListenAddress,
  validatePassword,
} from './passwordPolicy'

type SetupWizardProps = {
  clientIp: string
  onCompleted: () => void
}

type WizardStep = 0 | 1 | 2 | 3

export function SetupWizard({ clientIp, onCompleted }: SetupWizardProps) {
  const [step, setStep] = useState<WizardStep>(0)
  const [username, setUsername] = useState('Admin')
  const [password, setPassword] = useState('')
  const [passwordConfirm, setPasswordConfirm] = useState('')
  const [setupTotp, setSetupTotp] = useState(true)
  const [totpSecret, setTotpSecret] = useState('')
  const [totpUrl, setTotpUrl] = useState('')
  const [totpCode, setTotpCode] = useState('')
  const [totpConfirmed, setTotpConfirmed] = useState(false)
  const [qrDataUrl, setQrDataUrl] = useState('')
  const [network, setNetwork] = useState<NetworkSettings>(DEFAULT_NETWORK_SETTINGS)
  const [rulesText, setRulesText] = useState('')
  const [lockoutWarning, setLockoutWarning] = useState<string | null>(null)
  const [security, setSecurity] = useState<SecuritySettings>(
    DEFAULT_SECURITY_SETTINGS,
  )
  const [errorMessage, setErrorMessage] = useState<string | null>(null)
  const [isSubmitting, setIsSubmitting] = useState(false)

  useEffect(() => {
    if (!totpUrl) {
      setQrDataUrl('')
      return
    }
    let cancelled = false
    void import('qrcode').then(async (qrcode) => {
      const dataUrl = await qrcode.toDataURL(totpUrl, { width: 220, margin: 1 })
      if (!cancelled) {
        setQrDataUrl(dataUrl)
      }
    })
    return () => {
      cancelled = true
    }
  }, [totpUrl])

  useEffect(() => {
    if (step !== 2) {
      return
    }
    const rules = rulesText
      .split('\n')
      .map((line) => line.trim())
      .filter(Boolean)
    const draft: NetworkSettings = { ...network, rules }
    let cancelled = false
    void previewNetworkAccess(draft)
      .then((preview) => {
        if (cancelled) {
          return
        }
        if (preview.would_lock_out) {
          setLockoutWarning(
            preview.reason ||
              `These rules may lock out your current IP (${preview.client_ip}).`,
          )
        } else {
          setLockoutWarning(null)
        }
      })
      .catch(() => {
        if (!cancelled) {
          setLockoutWarning(null)
        }
      })
    return () => {
      cancelled = true
    }
  }, [step, network, rulesText])

  async function handleAdminNext() {
    setErrorMessage(null)
    const passwordError = validatePassword(password, username)
    if (passwordError) {
      setErrorMessage(passwordError)
      return
    }
    if (password !== passwordConfirm) {
      setErrorMessage('Passwords do not match')
      return
    }

    if (!setupTotp) {
      setTotpSecret('')
      setTotpConfirmed(false)
      setStep(2)
      return
    }

    if (!totpConfirmed) {
      try {
        setIsSubmitting(true)
        if (!totpSecret) {
          const began = await beginSetupTOTP(username.trim() || 'Admin')
          setTotpSecret(began.secret)
          setTotpUrl(began.otpauth_url)
          return
        }
        if (!totpCode.trim()) {
          setErrorMessage('Enter the TOTP code from your authenticator')
          return
        }
        await verifySetupTOTP(totpSecret, totpCode.trim())
        setTotpConfirmed(true)
        setSecurity((previous) => ({ ...previous, totp_enabled: true }))
        setStep(2)
      } catch (error) {
        setErrorMessage(
          error instanceof Error ? error.message : 'TOTP setup failed',
        )
      } finally {
        setIsSubmitting(false)
      }
      return
    }

    setStep(2)
  }

  function handleNetworkNext() {
    setErrorMessage(null)
    const listenError = validateListenAddress(network.listen_address)
    if (listenError) {
      setErrorMessage(listenError)
      return
    }
    const hostnameError = validateHostname(network.public_hostname)
    if (hostnameError) {
      setErrorMessage(hostnameError)
      return
    }
    if (lockoutWarning) {
      setErrorMessage(
        `${lockoutWarning} Adjust the rules before continuing.`,
      )
      return
    }
    const rules = rulesText
      .split('\n')
      .map((line) => line.trim())
      .filter(Boolean)
    setNetwork((previous) => ({ ...previous, rules }))
    setStep(3)
  }

  async function handleFinish() {
    setErrorMessage(null)
    setIsSubmitting(true)
    try {
      const rules = rulesText
        .split('\n')
        .map((line) => line.trim())
        .filter(Boolean)
      const finalSecurity = totpConfirmed
        ? { ...security, totp_enabled: true }
        : security
      await completeSetup({
        username: username.trim() || 'Admin',
        password,
        totp_secret: totpConfirmed ? totpSecret : '',
        totp_confirmed: totpConfirmed,
        network: { ...network, rules },
        security: finalSecurity,
      })
      onCompleted()
    } catch (error) {
      setErrorMessage(
        error instanceof Error ? error.message : 'Setup failed',
      )
    } finally {
      setIsSubmitting(false)
    }
  }

  return (
    <div className="wizard-shell">
      <div className="wizard-card">
        <p className="wizard-brand">Cluster Canvas</p>
        <h1 className="wizard-title">Setup wizard</h1>
        <p className="wizard-step-indicator">Step {step + 1} of 4</p>

        {errorMessage ? (
          <p className="wizard-error" role="alert">
            {errorMessage}
          </p>
        ) : null}

        {step === 0 ? (
          <div className="wizard-body">
            <h2>Welcome</h2>
            <p>
              Before you can use Cluster Canvas, a few settings need to be
              filled in: an administrator account, network access rules, and
              server security policy.
            </p>
            <p>
              This wizard walks through those steps once. After it finishes you
              will sign in with the admin account you create.
            </p>
            <div className="wizard-actions">
              <button
                type="button"
                className="groups-save"
                onClick={() => setStep(1)}
              >
                Continue
              </button>
            </div>
          </div>
        ) : null}

        {step === 1 ? (
          <div className="wizard-body">
            <h2>Administrator account</h2>
            <div className="config-field">
              <label htmlFor="setup-username">Login name</label>
              <input
                id="setup-username"
                className="config-input"
                value={username}
                onChange={(event) => setUsername(event.target.value)}
              />
            </div>
            <div className="config-field">
              <label htmlFor="setup-password">Password</label>
              <input
                id="setup-password"
                className="config-input"
                type="password"
                value={password}
                onChange={(event) => setPassword(event.target.value)}
              />
              <p className="config-hint">
                At least 14 characters, or a passphrase of at least 5 words.
                Maximum 256 characters.
              </p>
            </div>
            <div className="config-field">
              <label htmlFor="setup-password-confirm">Confirm password</label>
              <input
                id="setup-password-confirm"
                className="config-input"
                type="password"
                value={passwordConfirm}
                onChange={(event) => setPasswordConfirm(event.target.value)}
              />
            </div>
            <div className="config-field">
              <label className="permission-option" htmlFor="setup-totp">
                <input
                  id="setup-totp"
                  type="checkbox"
                  checked={setupTotp}
                  onChange={(event) => {
                    setSetupTotp(event.target.checked)
                    setTotpConfirmed(false)
                    setTotpSecret('')
                    setTotpUrl('')
                    setTotpCode('')
                  }}
                />
                Set up TOTP now (recommended)
              </label>
            </div>

            {setupTotp && totpSecret ? (
              <div className="totp-setup">
                {qrDataUrl ? (
                  <img
                    className="totp-qr"
                    src={qrDataUrl}
                    alt="TOTP QR code"
                    width={220}
                    height={220}
                  />
                ) : (
                  <p className="config-hint">Generating QR code…</p>
                )}
                <p className="config-hint">
                  Or copy this secret into your authenticator:
                </p>
                <code className="totp-secret">{totpSecret}</code>
                <button
                  type="button"
                  className="config-action-revert"
                  onClick={() => void navigator.clipboard.writeText(totpUrl || totpSecret)}
                >
                  Copy setup URI
                </button>
                <div className="config-field">
                  <label htmlFor="setup-totp-code">Verification code</label>
                  <input
                    id="setup-totp-code"
                    className="config-input"
                    value={totpCode}
                    onChange={(event) => setTotpCode(event.target.value)}
                    inputMode="numeric"
                    autoComplete="one-time-code"
                  />
                </div>
              </div>
            ) : null}

            <div className="wizard-actions">
              <button
                type="button"
                className="config-action-revert"
                onClick={() => setStep(0)}
              >
                Back
              </button>
              <button
                type="button"
                className="groups-save"
                disabled={isSubmitting}
                onClick={() => void handleAdminNext()}
              >
                {setupTotp && !totpSecret
                  ? 'Continue to TOTP'
                  : setupTotp && !totpConfirmed
                    ? 'Verify TOTP'
                    : 'Next'}
              </button>
            </div>
          </div>
        ) : null}

        {step === 2 ? (
          <div className="wizard-body">
            <h2>Network setup</h2>
            <div className="config-field">
              <label htmlFor="setup-listen">Listen address</label>
              <input
                id="setup-listen"
                className="config-input"
                value={network.listen_address}
                onChange={(event) =>
                  setNetwork((previous) => ({
                    ...previous,
                    listen_address: event.target.value,
                  }))
                }
              />
              <p className="config-hint">
                Default 0.0.0.0 (all interfaces). Applied on next process
                restart.
              </p>
            </div>
            <div className="config-field">
              <label htmlFor="setup-hostname">Public hostname</label>
              <input
                id="setup-hostname"
                className="config-input"
                placeholder="admin.mydomain.ext"
                value={network.public_hostname}
                onChange={(event) =>
                  setNetwork((previous) => ({
                    ...previous,
                    public_hostname: event.target.value,
                  }))
                }
              />
              <p className="config-hint">
                Recommended for production behind a reverse proxy (HTTPS). Leave
                empty for local/remotedev access by IP address — filling this in
                requires visiting the UI via that exact hostname.
              </p>
            </div>
            <div className="config-field">
              <label htmlFor="setup-access-mode">Access mode</label>
              <select
                id="setup-access-mode"
                className="theme-select"
                value={network.access_mode}
                onChange={(event) =>
                  setNetwork((previous) => ({
                    ...previous,
                    access_mode: event.target.value as AccessMode,
                  }))
                }
              >
                <option value="open">Open (no IP filter)</option>
                <option value="whitelist">Whitelist (deny non-matching)</option>
                <option value="blacklist">Blacklist (deny matching)</option>
              </select>
            </div>
            {network.access_mode !== 'open' ? (
              <div className="config-field">
                <label htmlFor="setup-rules">
                  IP / CIDR rules (one per line)
                </label>
                <textarea
                  id="setup-rules"
                  className="config-input wizard-rules"
                  rows={5}
                  value={rulesText}
                  onChange={(event) => setRulesText(event.target.value)}
                />
                <p className="config-hint">Your current IP: {clientIp || 'unknown'}</p>
                {lockoutWarning ? (
                  <p className="wizard-error" role="status">
                    {lockoutWarning}
                  </p>
                ) : null}
              </div>
            ) : null}
            <div className="wizard-actions">
              <button
                type="button"
                className="config-action-revert"
                onClick={() => setStep(1)}
              >
                Back
              </button>
              <button
                type="button"
                className="groups-save"
                onClick={handleNetworkNext}
              >
                Next
              </button>
            </div>
          </div>
        ) : null}

        {step === 3 ? (
          <div className="wizard-body">
            <h2>Server settings</h2>
            <div className="config-field">
              <label htmlFor="setup-idle">Idle timeout (minutes)</label>
              <input
                id="setup-idle"
                className="config-input"
                type="number"
                min={1}
                max={240}
                value={security.idle_timeout_minutes}
                onChange={(event) =>
                  setSecurity((previous) => ({
                    ...previous,
                    idle_timeout_minutes: Number(event.target.value) || 0,
                  }))
                }
              />
            </div>
            <div className="config-field">
              <label htmlFor="setup-lifetime">Session lifetime (hours)</label>
              <input
                id="setup-lifetime"
                className="config-input"
                type="number"
                min={1}
                value={security.session_lifetime_hours}
                onChange={(event) =>
                  setSecurity((previous) => ({
                    ...previous,
                    session_lifetime_hours: Number(event.target.value) || 0,
                  }))
                }
              />
            </div>
            <div className="config-field">
              <label className="permission-option" htmlFor="setup-totp-server">
                <input
                  id="setup-totp-server"
                  type="checkbox"
                  checked={security.totp_enabled}
                  disabled={totpConfirmed}
                  onChange={(event) =>
                    setSecurity((previous) => ({
                      ...previous,
                      totp_enabled: event.target.checked,
                    }))
                  }
                />
                Enable TOTP
              </label>
              {totpConfirmed ? (
                <p className="config-hint">
                  Locked on because the admin account enrolled TOTP.
                </p>
              ) : null}
            </div>
            <div className="config-field">
              <label className="permission-option" htmlFor="setup-reauth">
                <input
                  id="setup-reauth"
                  type="checkbox"
                  checked={security.reauth_sensitive_actions}
                  onChange={(event) =>
                    setSecurity((previous) => ({
                      ...previous,
                      reauth_sensitive_actions: event.target.checked,
                    }))
                  }
                />
                Re-auth for sensitive actions
              </label>
            </div>
            <div className="config-field">
              <label htmlFor="setup-reauth-grace">
                Re-auth grace period (minutes)
              </label>
              <input
                id="setup-reauth-grace"
                className="config-input"
                type="number"
                min={0}
                disabled={!security.reauth_sensitive_actions}
                value={security.reauth_grace_minutes}
                onChange={(event) =>
                  setSecurity((previous) => ({
                    ...previous,
                    reauth_grace_minutes: Number(event.target.value) || 0,
                  }))
                }
              />
            </div>
            <div className="wizard-actions">
              <button
                type="button"
                className="config-action-revert"
                onClick={() => setStep(2)}
              >
                Back
              </button>
              <button
                type="button"
                className="groups-save"
                disabled={isSubmitting}
                onClick={() => void handleFinish()}
              >
                Finish setup
              </button>
            </div>
          </div>
        ) : null}
      </div>
    </div>
  )
}
