'use client'

import { useMemo, useState } from 'react'
import { useRouter } from 'next/navigation'

import { useI18n } from '@/components/providers/i18n-provider'
import { Button, Field, Input, Notice, Switch } from '@/components/ui/controls'
import { Meter, Panel, PanelBody, PanelHeader } from '@/components/ui/display'
import { ApiClientError, api, failureMessage, fieldErrorMessage } from '@/lib/api/client'
import { DEFAULT_RISK_WEIGHTS, RISK_WEIGHT_SETTING_KEYS } from '@/lib/engine/risk'

export interface SettingRow {
  key: string
  value: string
  valueType: string
  groupKey: string
  label: string
  labelAr: string
  description: string
  descriptionAr: string
  minValue: number | null
  maxValue: number | null
}

const GROUP_ORDER = ['risk', 'escalation', 'prediction', 'runtime']

/**
 * Platform settings (§42).
 *
 * The risk weights are the important ones: they are inputs to every score the platform
 * produces, so the form shows the running total and states plainly that changing one
 * changes everything downstream. Bounds are enforced again on the server.
 */
export function SettingsForm({
  settings,
  canManage,
  preview,
}: {
  settings: SettingRow[]
  canManage: boolean
  preview: { assetCode: string; riskScore: number } | null
}) {
  const { t, locale, n } = useI18n()
  const router = useRouter()

  const [values, setValues] = useState<Record<string, string>>(() =>
    Object.fromEntries(settings.map((setting) => [setting.key, setting.value])),
  )
  const [saving, setSaving] = useState(false)
  const [message, setMessage] = useState<string | null>(null)
  const [error, setError] = useState<string | null>(null)
  const [fieldErrors, setFieldErrors] = useState<Record<string, string>>({})

  const dirty = useMemo(
    () => settings.some((setting) => values[setting.key] !== setting.value),
    [settings, values],
  )

  const stressWeightKeys = [
    RISK_WEIGHT_SETTING_KEYS.anomaly,
    RISK_WEIGHT_SETTING_KEYS.dna,
    RISK_WEIGHT_SETTING_KEYS.load,
    RISK_WEIGHT_SETTING_KEYS.thermal,
    RISK_WEIGHT_SETTING_KEYS.weather,
  ]
  const weightSum = stressWeightKeys.reduce((sum, key) => sum + (Number(values[key]) || 0), 0)

  const grouped = GROUP_ORDER.map((group) => ({
    group,
    items: settings.filter((setting) => setting.groupKey === group),
  })).filter((entry) => entry.items.length > 0)

  const save = async () => {
    if (!dirty || saving) return
    setSaving(true)
    setError(null)
    setMessage(null)
    setFieldErrors({})

    const changed = Object.fromEntries(
      settings
        .filter((setting) => values[setting.key] !== setting.value)
        .map((setting) => [setting.key, values[setting.key]]),
    )

    try {
      await api.patch('/api/settings', { values: changed })
      setMessage(t('common.saved'))
      router.refresh()
    } catch (caught) {
      if (caught instanceof ApiClientError) {
        setError(failureMessage(caught.failure, locale))
        if (caught.failure.details) setFieldErrors(caught.failure.details)
      } else {
        setError(t('common.serverError'))
      }
    } finally {
      setSaving(false)
    }
  }

  const restoreDefaults = () => {
    const defaults: Record<string, string> = {}
    for (const [field, key] of Object.entries(RISK_WEIGHT_SETTING_KEYS)) {
      defaults[key] = String(DEFAULT_RISK_WEIGHTS[field as keyof typeof DEFAULT_RISK_WEIGHTS])
    }
    setValues((current) => ({ ...current, ...defaults }))
  }

  return (
    <div className="space-y-6">
      {error ? <Notice tone="danger">{error}</Notice> : null}
      {message ? <Notice tone="success">{message}</Notice> : null}

      {grouped.map(({ group, items }) => (
        <Panel key={group}>
          <PanelHeader
            title={t(`settings.groups.${group}`)}
            subtitle={group === 'risk' ? t('settings.riskNote') : undefined}
            action={
              group === 'risk' && canManage ? (
                <Button size="sm" variant="ghost" onClick={restoreDefaults}>
                  {t('settings.restoreDefaults')}
                </Button>
              ) : null
            }
          />
          <PanelBody className="space-y-4">
            {group === 'risk' ? (
              <div className="rounded-lg border border-border bg-surface-2/40 px-4 py-3">
                <div className="flex flex-wrap items-baseline justify-between gap-2">
                  <span className="text-xs text-text-muted">
                    {t('settings.weightSum', { value: n(weightSum, { maximumFractionDigits: 2 }) })}
                  </span>
                  <span className="text-[11px] text-text-faint">{t('settings.weightSumNote')}</span>
                </div>
                <Meter value={Math.min(100, weightSum * 100)} className="mt-2" />
              </div>
            ) : null}

            <div className="grid gap-4 sm:grid-cols-2">
              {items.map((setting) => (
                <Field
                  key={setting.key}
                  label={locale === 'ar' ? setting.labelAr : setting.label}
                  htmlFor={setting.key}
                  hint={locale === 'ar' ? setting.descriptionAr : setting.description}
                  error={fieldErrorMessage(fieldErrors[setting.key], t)}
                >
                  {setting.valueType === 'boolean' ? (
                    <Switch
                      id={setting.key}
                      checked={values[setting.key] === 'true'}
                      disabled={!canManage}
                      onChange={(next) =>
                        setValues((current) => ({ ...current, [setting.key]: String(next) }))
                      }
                      label={values[setting.key] === 'true' ? t('common.yes') : t('common.no')}
                    />
                  ) : (
                    <Input
                      id={setting.key}
                      type="number"
                      dir="ltr"
                      step={setting.maxValue !== null && setting.maxValue <= 2 ? 0.01 : 1}
                      min={setting.minValue ?? undefined}
                      max={setting.maxValue ?? undefined}
                      value={values[setting.key]}
                      disabled={!canManage}
                      invalid={Boolean(fieldErrors[setting.key])}
                      onChange={(event) =>
                        setValues((current) => ({ ...current, [setting.key]: event.target.value }))
                      }
                    />
                  )}
                </Field>
              ))}
            </div>
          </PanelBody>
        </Panel>
      ))}

      {preview ? (
        <Panel>
          <PanelHeader title={t('settings.preview')} subtitle={t('settings.previewNote')} />
          <PanelBody>
            <div className="flex flex-wrap items-center justify-between gap-3">
              <span className="font-mono text-sm text-brand">{preview.assetCode}</span>
              <span className="tnum text-2xl font-semibold text-text">
                {n(preview.riskScore, { maximumFractionDigits: 1 })}%
              </span>
            </div>
            <Meter value={preview.riskScore} className="mt-3" />
          </PanelBody>
        </Panel>
      ) : null}

      {canManage ? (
        <div className="sticky bottom-4 flex justify-end">
          <Button onClick={save} loading={saving} disabled={!dirty} size="lg">
            {saving ? t('common.saving') : t('common.save')}
          </Button>
        </div>
      ) : (
        <Notice tone="info">{t('common.permissionDeniedBody')}</Notice>
      )}
    </div>
  )
}
