import { useEffect, useState } from "react"
import { Plus, X } from "lucide-react"

import { useArcadiaClient } from "@crema/arcadia-core-client"
import { useToast } from "@crema/notification-ui"

import { TenantSection, Field } from "~/components/tenant-detail/section"
import { DataState } from "~/components/data-state"
import { Button } from "~/components/ui/button"
import { Input } from "~/components/ui/input"
import { NativeSelect, NativeSelectOption } from "~/components/ui/native-select"
import { Card, CardContent, CardHeader, CardTitle } from "~/components/ui/card"
import {
  listUsage,
  updatePlan,
  TENANT_PLANS,
  type UsageRow,
} from "~/lib/arcadia/tenants"
import type { TenantTabProps } from "~/routes/tenants.$id"

// One editable limit row. `locked` marks a key that already existed on the
// tenant (its name is fixed — you edit the value or remove the row); new rows
// added with "Add limit" have an editable key.
type LimitRow = { id: number; key: string; value: string; locked: boolean }

let rowSeq = 0
const nextRowId = () => ++rowSeq

function rowsFromLimits(limits: Record<string, unknown> | undefined): LimitRow[] {
  return Object.entries(limits ?? {}).map(([key, value]) => ({
    id: nextRowId(),
    key,
    value: String(value ?? ""),
    locked: true,
  }))
}

// Collapse the editable rows into the Record<string, number> the server wants.
// Blank keys are dropped; non-numeric values coerce to 0 (Number("") === 0 too).
function buildLimits(rows: LimitRow[]): Record<string, number> {
  const out: Record<string, number> = {}
  for (const row of rows) {
    const key = row.key.trim()
    if (!key) continue
    out[key] = Number(row.value)
  }
  return out
}

function normaliseLimits(limits: Record<string, unknown> | undefined): Record<string, number> {
  const out: Record<string, number> = {}
  for (const [key, value] of Object.entries(limits ?? {})) out[key] = Number(value)
  return out
}

export function PlanTab({ tenant, reload }: TenantTabProps) {
  const arcadia = useArcadiaClient()
  const toast = useToast()

  const currentPlan = tenant.plan?.name ?? ""
  const [plan, setPlan] = useState(currentPlan || TENANT_PLANS[0])
  const [rows, setRows] = useState<LimitRow[]>(() => rowsFromLimits(tenant.plan?.limits))
  const [saving, setSaving] = useState(false)
  const [error, setError] = useState<unknown>(null)

  const originalLimits = normaliseLimits(tenant.plan?.limits)
  const dirty =
    plan !== currentPlan ||
    JSON.stringify(buildLimits(rows)) !== JSON.stringify(originalLimits)

  const setRowKey = (id: number, key: string) =>
    setRows((rs) => rs.map((r) => (r.id === id ? { ...r, key } : r)))
  const setRowValue = (id: number, value: string) =>
    setRows((rs) => rs.map((r) => (r.id === id ? { ...r, value } : r)))
  const removeRow = (id: number) => setRows((rs) => rs.filter((r) => r.id !== id))
  const addRow = () =>
    setRows((rs) => [...rs, { id: nextRowId(), key: "", value: "", locked: false }])

  const save = async () => {
    setSaving(true)
    setError(null)
    try {
      await updatePlan(arcadia, tenant.id, {
        plan,
        plan_limits: buildLimits(rows),
      })
      await reload()
      toast.success("Plan updated")
    } catch (err) {
      setError(err)
    } finally {
      setSaving(false)
    }
  }

  return (
    <div className="flex flex-col gap-6">
      <TenantSection
        title="Plan"
        description="The tenant's plan and its quota limits are saved together. The plan slug must be one the server recognises."
        onSubmit={save}
        saving={saving}
        error={error}
        errorContext="update the plan"
        dirty={dirty}
        dataAction="tenant-detail-plan-save"
      >
        <Field label="Plan" htmlFor="tenant-detail-plan-select">
          <NativeSelect
            id="tenant-detail-plan-select"
            className="w-full"
            value={plan}
            onChange={(e) => setPlan(e.target.value)}
            data-action="tenant-detail-plan-select"
          >
            {TENANT_PLANS.map((p) => (
              <NativeSelectOption key={p} value={p}>
                {p}
              </NativeSelectOption>
            ))}
          </NativeSelect>
        </Field>

        <Field
          label="Plan limits"
          hint="Numeric quotas attached to this plan (e.g. users, storage_gb). Saved with the plan above."
        >
          <div className="flex flex-col gap-2">
            {rows.length === 0 ? (
              <p className="text-sm text-muted-foreground">No limits set.</p>
            ) : (
              rows.map((row) => (
                <div key={row.id} className="flex items-center gap-2">
                  <Input
                    className="flex-1"
                    placeholder="key"
                    value={row.key}
                    readOnly={row.locked}
                    disabled={row.locked}
                    onChange={(e) => setRowKey(row.id, e.target.value)}
                    aria-label="Limit key"
                    data-action="tenant-detail-plan-limit-key"
                  />
                  <Input
                    className="w-32"
                    type="number"
                    inputMode="numeric"
                    placeholder="value"
                    value={row.value}
                    onChange={(e) => setRowValue(row.id, e.target.value)}
                    aria-label="Limit value"
                    data-action="tenant-detail-plan-limit-value"
                  />
                  <Button
                    type="button"
                    variant="ghost"
                    size="icon-sm"
                    onClick={() => removeRow(row.id)}
                    aria-label="Remove limit"
                    data-action="tenant-detail-plan-limit-remove"
                  >
                    <X className="size-4" />
                  </Button>
                </div>
              ))
            )}

            <div>
              <Button
                type="button"
                variant="outline"
                size="sm"
                onClick={addRow}
                data-action="tenant-detail-plan-limit-add"
              >
                <Plus className="size-4" />
                Add limit
              </Button>
            </div>
          </div>
        </Field>
      </TenantSection>

      <PlanUsage tenantId={tenant.id} />
    </div>
  )
}

// Read-only usage-vs-quota panel. Loads independently so a metering failure
// never blanks the plan form above it.
function PlanUsage({ tenantId }: { tenantId: string }) {
  const arcadia = useArcadiaClient()
  const [rows, setRows] = useState<UsageRow[]>([])
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<unknown>(null)

  const load = async () => {
    setError(null)
    setLoading(true)
    try {
      setRows(await listUsage(arcadia, tenantId))
    } catch (err) {
      setError(err)
    } finally {
      setLoading(false)
    }
  }

  useEffect(() => {
    load()
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [tenantId])

  return (
    <Card>
      <CardHeader>
        <CardTitle>Usage</CardTitle>
      </CardHeader>
      <CardContent>
        <DataState
          loading={loading}
          error={error}
          isEmpty={rows.length === 0}
          onRetry={load}
          loadingLabel="Loading usage…"
          empty={
            <div className="py-6 text-center text-sm text-muted-foreground">
              No metered usage yet.
            </div>
          }
        >
          <ul className="flex flex-col divide-y divide-border">
            {rows.map((row) => (
              <li key={row.category} className="flex flex-col gap-1 py-3 first:pt-0 last:pb-0">
                <div className="font-medium capitalize">{row.category}</div>
                <div className="grid gap-1 text-sm text-muted-foreground sm:grid-cols-3">
                  <UsageMeter
                    label="This minute"
                    used={row.usage.minute}
                    limit={row.quota.enabled ? row.quota.calls_per_minute : null}
                  />
                  <UsageMeter
                    label="Today"
                    used={row.usage.day}
                    limit={row.quota.enabled ? row.quota.calls_per_day : null}
                  />
                  <UsageMeter
                    label="This month"
                    used={row.usage.month}
                    limit={row.quota.enabled ? row.quota.calls_per_month : null}
                  />
                </div>
              </li>
            ))}
          </ul>
        </DataState>
      </CardContent>
    </Card>
  )
}

function UsageMeter({
  label,
  used,
  limit,
}: {
  label: string
  used: number
  limit: number | null
}) {
  return (
    <div>
      <span className="text-xs uppercase tracking-wider">{label}</span>
      <div className="text-foreground">
        {used} {limit != null ? `/ ${limit}` : "/ no limit"}
      </div>
    </div>
  )
}
