'use client'

import { useCallback, useEffect, useMemo, useState } from 'react'
import {
  validateSecuritySettings,
  type SecurityCenterData,
  type SecuritySettings,
} from '@actuate-media/cms-core/security-center'
import { cmsApi } from '../../lib/api.js'
import type { ValidationIssue } from './useGeneralSettings.js'

/** The subset of security policy the tab can actually edit + enforce. */
export interface SecurityForm {
  mfaRequired: boolean
  mfaGracePeriodDays: number
  maxConcurrentSessions: number
}

type SaveState = 'idle' | 'saving' | 'success' | 'error'

const EMPTY_FORM: SecurityForm = {
  mfaRequired: false,
  mfaGracePeriodDays: 7,
  maxConcurrentSessions: 5,
}

function formFromSettings(s: SecuritySettings): SecurityForm {
  return {
    mfaRequired: s.mfa.required,
    mfaGracePeriodDays: s.mfa.gracePeriodDays,
    maxConcurrentSessions: s.session.maxConcurrentSessions,
  }
}

function formToSettings(f: SecurityForm): SecuritySettings {
  return {
    mfa: { required: f.mfaRequired, gracePeriodDays: f.mfaGracePeriodDays },
    session: { maxConcurrentSessions: f.maxConcurrentSessions },
  }
}

export interface UseSecuritySettings {
  loading: boolean
  loadError: string | null
  data: SecurityCenterData | null
  form: SecurityForm
  setField: <K extends keyof SecurityForm>(key: K, value: SecurityForm[K]) => void
  dirty: boolean
  issues: ValidationIssue[]
  hasErrors: boolean
  canEdit: boolean
  saveState: SaveState
  saveError: string | null
  save: () => Promise<void>
  reset: () => void
  refetch: () => void
  revokeState: 'idle' | 'working' | 'done' | 'error'
  revokeAllOtherSessions: () => Promise<number | null>
}

/**
 * Loads the Security Center (`GET /security`) — computed posture, cross-module
 * summaries, secret/encryption verdicts — and tracks the small editable policy
 * (MFA requirement + grace, concurrent-session cap). Save is lockout-safe: the
 * client mirrors the server's MFA guard so the operator gets immediate feedback,
 * and the server re-checks authoritatively.
 */
export function useSecuritySettings(canEdit: boolean): UseSecuritySettings {
  const [loading, setLoading] = useState(true)
  const [loadError, setLoadError] = useState<string | null>(null)
  const [data, setData] = useState<SecurityCenterData | null>(null)
  const [baseline, setBaseline] = useState<SecurityForm>(EMPTY_FORM)
  const [form, setForm] = useState<SecurityForm>(EMPTY_FORM)
  const [saveState, setSaveState] = useState<SaveState>('idle')
  const [saveError, setSaveError] = useState<string | null>(null)
  const [revokeState, setRevokeState] = useState<'idle' | 'working' | 'done' | 'error'>('idle')
  const [reloadKey, setReloadKey] = useState(0)

  useEffect(() => {
    let cancelled = false
    setLoading(true)
    setLoadError(null)
    cmsApi<SecurityCenterData>('/security')
      .then((res) => {
        if (cancelled) return
        if (res.error || !res.data) {
          setLoadError(res.error ?? 'Failed to load security settings.')
          return
        }
        setData(res.data)
        const f = formFromSettings(res.data.settings)
        setBaseline(f)
        setForm(f)
      })
      .catch(() => {
        if (!cancelled) setLoadError('Failed to load security settings.')
      })
      .finally(() => {
        if (!cancelled) setLoading(false)
      })
    return () => {
      cancelled = true
    }
  }, [reloadKey])

  const setField = useCallback(<K extends keyof SecurityForm>(key: K, value: SecurityForm[K]) => {
    setForm((prev) => ({ ...prev, [key]: value }))
    setSaveState('idle')
  }, [])

  const dirty = useMemo(
    () => (Object.keys(form) as Array<keyof SecurityForm>).some((k) => form[k] !== baseline[k]),
    [form, baseline],
  )

  const issues = useMemo<ValidationIssue[]>(() => {
    const list = validateSecuritySettings(formToSettings(form))
    // Client mirror of the server's lockout-safe MFA guard: block enabling
    // org-wide MFA when the current admin has not set up MFA themselves.
    if (form.mfaRequired && !baseline.mfaRequired && data && !data.viewerHasMfa) {
      list.push({
        field: 'mfaRequired',
        message:
          'Set up MFA for your own account before requiring it for everyone — otherwise you would lock yourself out.',
        severity: 'error',
      })
    }
    return list
  }, [form, baseline.mfaRequired, data])

  const hasErrors = issues.some((i) => i.severity === 'error')

  const save = useCallback(async () => {
    if (!canEdit || hasErrors || !dirty) return
    setSaveState('saving')
    setSaveError(null)
    try {
      const res = await cmsApi<SecurityCenterData>('/security', {
        method: 'PUT',
        body: JSON.stringify(formToSettings(form)),
      })
      if (res.error || !res.data) throw new Error(res.error ?? 'Failed to save security settings.')
      setData(res.data)
      const f = formFromSettings(res.data.settings)
      setBaseline(f)
      setForm(f)
      setSaveState('success')
    } catch (err) {
      setSaveState('error')
      setSaveError(err instanceof Error ? err.message : 'Failed to save security settings.')
    }
  }, [canEdit, hasErrors, dirty, form])

  const reset = useCallback(() => {
    setForm(baseline)
    setSaveState('idle')
    setSaveError(null)
  }, [baseline])

  const refetch = useCallback(() => setReloadKey((k) => k + 1), [])

  const revokeAllOtherSessions = useCallback(async (): Promise<number | null> => {
    setRevokeState('working')
    try {
      const res = await cmsApi<{ revoked: number }>('/security/sessions/revoke-all', {
        method: 'POST',
      })
      if (res.error) throw new Error(res.error)
      setRevokeState('done')
      // Refresh the active-session count.
      setReloadKey((k) => k + 1)
      return res.data?.revoked ?? 0
    } catch {
      setRevokeState('error')
      return null
    }
  }, [])

  return {
    loading,
    loadError,
    data,
    form,
    setField,
    dirty,
    issues,
    hasErrors,
    canEdit,
    saveState,
    saveError,
    save,
    reset,
    refetch,
    revokeState,
    revokeAllOtherSessions,
  }
}
