import { useState } from "react"

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

import { TenantSection, Field } from "~/components/tenant-detail/section"
import { Input } from "~/components/ui/input"
import { Textarea } from "~/components/ui/textarea"
import { updateBranding } from "~/lib/arcadia/tenants"
import type { TenantTabProps } from "~/routes/tenants.$id"

/**
 * Tenant branding: logo/favicon URLs, the three brand colours, and a custom-CSS
 * override. All fields are optional; clearing one and saving sends `null` so it
 * clears server-side (the server accepts null and validates any colour it does
 * get against a `#rrggbb` hex).
 */
export function BrandingTab({ tenant, reload }: TenantTabProps) {
  const arcadia = useArcadiaClient()
  const toast = useToast()
  const b = tenant.branding

  const [logoUrl, setLogoUrl] = useState(b.logo_url ?? "")
  const [faviconUrl, setFaviconUrl] = useState(b.favicon_url ?? "")
  const [primary, setPrimary] = useState(b.primary_color ?? "")
  const [secondary, setSecondary] = useState(b.secondary_color ?? "")
  const [accent, setAccent] = useState(b.accent_color ?? "")
  const [customCss, setCustomCss] = useState(b.custom_css ?? "")

  const [saving, setSaving] = useState(false)
  const [error, setError] = useState<unknown>(null)

  const dirty =
    logoUrl !== (b.logo_url ?? "") ||
    faviconUrl !== (b.favicon_url ?? "") ||
    primary !== (b.primary_color ?? "") ||
    secondary !== (b.secondary_color ?? "") ||
    accent !== (b.accent_color ?? "") ||
    customCss !== (b.custom_css ?? "")

  const save = async () => {
    setSaving(true)
    setError(null)
    try {
      await updateBranding(arcadia, tenant.id, {
        logo_url: emptyToNull(logoUrl),
        favicon_url: emptyToNull(faviconUrl),
        primary_color: emptyToNull(primary),
        secondary_color: emptyToNull(secondary),
        accent_color: emptyToNull(accent),
        custom_css: customCss.trim() === "" ? null : customCss,
      })
      await reload()
      toast.success("Branding updated")
    } catch (err) {
      setError(err)
    } finally {
      setSaving(false)
    }
  }

  return (
    <TenantSection
      title="Branding"
      description="How this tenant's apps present themselves. Leave a field blank to fall back to the platform default; clearing a saved value removes it."
      onSubmit={save}
      saving={saving}
      error={error}
      errorContext="update branding"
      dirty={dirty}
      dataAction="tenant-detail-branding-save"
    >
      <Field
        label="Logo URL"
        htmlFor="branding-logo-url"
        hint="Publicly reachable image URL shown in the tenant's app header."
      >
        <Input
          id="branding-logo-url"
          type="url"
          value={logoUrl}
          onChange={(e) => setLogoUrl(e.target.value)}
          placeholder="https://…"
          data-action="tenant-detail-branding-logo-url"
        />
      </Field>

      <Field
        label="Favicon URL"
        htmlFor="branding-favicon-url"
        hint="Publicly reachable .ico/.png used as the browser tab icon."
      >
        <Input
          id="branding-favicon-url"
          type="url"
          value={faviconUrl}
          onChange={(e) => setFaviconUrl(e.target.value)}
          placeholder="https://…"
          data-action="tenant-detail-branding-favicon-url"
        />
      </Field>

      <ColorField
        label="Primary color"
        id="branding-primary-color"
        value={primary}
        onChange={setPrimary}
        dataAction="tenant-detail-branding-primary-color"
      />
      <ColorField
        label="Secondary color"
        id="branding-secondary-color"
        value={secondary}
        onChange={setSecondary}
        dataAction="tenant-detail-branding-secondary-color"
      />
      <ColorField
        label="Accent color"
        id="branding-accent-color"
        value={accent}
        onChange={setAccent}
        dataAction="tenant-detail-branding-accent-color"
      />

      <Field
        label="Custom CSS"
        htmlFor="branding-custom-css"
        hint="Injected into the tenant's apps. Applies verbatim — test before saving."
      >
        <Textarea
          id="branding-custom-css"
          value={customCss}
          onChange={(e) => setCustomCss(e.target.value)}
          rows={6}
          spellCheck={false}
          className="font-mono text-xs"
          placeholder=":root { --brand: #5b21b6; }"
          data-action="tenant-detail-branding-custom-css"
        />
      </Field>
    </TenantSection>
  )
}

/**
 * A hex-colour control: a native colour swatch and a text input kept in sync,
 * plus a live preview chip. The text field holds the source of truth (may be
 * empty or a partial/invalid hex mid-edit); the swatch falls back to black so
 * the picker always has something to show.
 */
function ColorField({
  label,
  id,
  value,
  onChange,
  dataAction,
}: {
  label: string
  id: string
  value: string
  onChange: (v: string) => void
  dataAction: string
}) {
  const trimmed = value.trim()
  const valid = /^#[0-9a-fA-F]{6}$/.test(trimmed)

  return (
    <Field label={label} htmlFor={id} hint="Hex like #5b21b6. Clear to remove.">
      <div className="flex items-center gap-2">
        <Input
          type="color"
          aria-label={`${label} swatch`}
          value={valid ? trimmed : "#000000"}
          onChange={(e) => onChange(e.target.value)}
          className="h-8 w-12 shrink-0 cursor-pointer p-1"
          data-action={`${dataAction}-swatch`}
        />
        <Input
          id={id}
          type="text"
          value={value}
          onChange={(e) => onChange(e.target.value)}
          placeholder="#000000"
          className="font-mono"
          data-action={dataAction}
        />
        <span
          aria-hidden="true"
          title={valid ? trimmed : "No colour"}
          className="size-8 shrink-0 rounded-lg border border-input"
          style={{ background: valid ? trimmed : "transparent" }}
        />
      </div>
    </Field>
  )
}

/** Trim to detect emptiness; a blank field clears server-side via null. */
function emptyToNull(s: string): string | null {
  return s.trim() === "" ? null : s.trim()
}
