import {
  type AdminProfileFlag,
  type AdminProfileRow,
  type AdminSetting,
  createInvite,
  deleteInvite,
  type InviteRecord,
  listAdminSettings,
  listAllProfiles,
  listInvites,
  setInviteDisabled,
  setUserFlag,
  updateAdminSetting,
} from '@chat-app/shared/admin';
import { extractErrorCode } from '@chat-app/shared/i18n';
import { useCallback, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';

import { Avatar } from '../components/Avatar';
import {
  AlertIcon,
  CopyIcon,
  PlusIcon,
  SpinnerIcon,
  TrashIcon,
} from '../components/icons';
import { supabase } from '../lib/supabase';

export function AdminPage() {
  const { t } = useTranslation(['app', 'errors']);
  const [settings, setSettings] = useState<AdminSetting[]>([]);
  const [invites, setInvites] = useState<InviteRecord[]>([]);
  const [users, setUsers] = useState<AdminProfileRow[]>([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  const refresh = useCallback(async () => {
    try {
      setLoading(true);
      const [s, i, u] = await Promise.all([
        listAdminSettings(supabase),
        listInvites(supabase),
        listAllProfiles(supabase),
      ]);
      setSettings(s);
      setInvites(i);
      setUsers(u);
      setError(null);
    } catch (err: unknown) {
      const code = extractErrorCode(err);
      setError(
        code
          ? t('errors:' + code, { defaultValue: t('errors:generic') })
          : err instanceof Error
            ? err.message
            : t('errors:generic'),
      );
    } finally {
      setLoading(false);
    }
  }, [t]);

  useEffect(() => {
    void refresh();
  }, [refresh]);

  return (
    <div className="min-h-full bg-surface-3 text-fg">
      <div className="mx-auto flex max-w-4xl flex-col gap-6 px-6 py-8">
      <header>
        <h1 className="font-display text-2xl font-semibold tracking-tight text-fg">
          {t('app:admin.title')}
        </h1>
      </header>

      {error && (
        <div
          role="alert"
          className="flex items-start gap-3 rounded-lg border border-rose-500/30 bg-rose-500/10 p-3 text-sm text-rose-700 dark:text-rose-100"
        >
          <AlertIcon className="mt-0.5 h-5 w-5 shrink-0 text-rose-500 dark:text-rose-400" />
          <p className="min-w-0 flex-1 break-words">{error}</p>
        </div>
      )}

      {loading ? (
        <div className="flex items-center gap-2 text-sm text-fg-muted">
          <SpinnerIcon className="h-4 w-4 text-accent" />
        </div>
      ) : (
        <>
          <SettingsSection settings={settings} onRefresh={refresh} />
          <InvitesSection invites={invites} onRefresh={refresh} />
          <UsersSection users={users} onRefresh={refresh} />
        </>
      )}
      </div>
    </div>
  );
}

function Section({ title, children, action }: { title: string; children: React.ReactNode; action?: React.ReactNode }) {
  return (
    <section className="rounded-2xl border border-line bg-surface-2 p-5">
      <header className="mb-4 flex items-center justify-between">
        <h2 className="text-xs font-semibold uppercase tracking-[0.1em] text-fg-muted">{title}</h2>
        {action}
      </header>
      {children}
    </section>
  );
}

// --- Settings --------------------------------------------------------------

function SettingsSection({ settings, onRefresh }: { settings: AdminSetting[]; onRefresh: () => Promise<void> }) {
  const { t } = useTranslation(['app']);
  const [busy, setBusy] = useState(false);

  const invitesEnabled = Boolean(settings.find((s) => s.key === 'invites_enabled')?.value);

  async function handleToggleInvites(next: boolean) {
    if (busy) return;
    setBusy(true);
    try {
      await updateAdminSetting(supabase, 'invites_enabled', next);
      await onRefresh();
    } catch (err: unknown) {
      console.error(err);
    } finally {
      setBusy(false);
    }
  }

  return (
    <Section title={t('app:admin.settings_title')}>
      <Toggle
        label={t('app:admin.invites_enabled')}
        hint={t('app:admin.invites_enabled_hint')}
        checked={invitesEnabled}
        disabled={busy}
        onChange={(v) => void handleToggleInvites(v)}
      />
    </Section>
  );
}

// --- Invites ---------------------------------------------------------------

function InvitesSection({ invites, onRefresh }: { invites: InviteRecord[]; onRefresh: () => Promise<void> }) {
  const { t } = useTranslation(['app']);
  const [busy, setBusy] = useState(false);
  const [copiedCode, setCopiedCode] = useState<string | null>(null);

  async function handleCreate() {
    if (busy) return;
    setBusy(true);
    try {
      await createInvite(supabase, {});
      await onRefresh();
    } catch (err: unknown) {
      console.error(err);
    } finally {
      setBusy(false);
    }
  }

  async function handleToggle(code: string, disabled: boolean) {
    try {
      await setInviteDisabled(supabase, code, !disabled);
      await onRefresh();
    } catch (err: unknown) {
      console.error(err);
    }
  }

  async function handleDelete(code: string) {
    if (!window.confirm(code + ' ?')) return;
    try {
      await deleteInvite(supabase, code);
      await onRefresh();
    } catch (err: unknown) {
      console.error(err);
    }
  }

  async function handleCopy(code: string) {
    try {
      await navigator.clipboard.writeText(code);
      setCopiedCode(code);
      window.setTimeout(() => setCopiedCode((c) => (c === code ? null : c)), 1400);
    } catch {
      /* ignore */
    }
  }

  return (
    <Section
      title={t('app:admin.invites_title')}
      action={
        <button
          type="button"
          onClick={() => void handleCreate()}
          disabled={busy}
          className="inline-flex cursor-pointer items-center gap-1.5 rounded-md bg-accent px-3 py-1.5 text-xs font-semibold text-accent-fg transition hover:brightness-110 disabled:opacity-60"
        >
          {busy ? <SpinnerIcon className="h-3.5 w-3.5" /> : <PlusIcon className="h-3.5 w-3.5" />}
          <span>{t('app:admin.invites_create')}</span>
        </button>
      }
    >
      {invites.length === 0 ? (
        <p className="text-sm text-fg-muted">{t('app:admin.invites_empty')}</p>
      ) : (
        <div className="overflow-x-auto">
          <table className="w-full text-left text-sm">
            <thead className="text-[10px] uppercase tracking-[0.1em] text-fg-muted">
              <tr>
                <th className="py-2 pr-3">{t('app:admin.invite_col_code')}</th>
                <th className="py-2 pr-3">{t('app:admin.invite_col_uses')}</th>
                <th className="py-2 pr-3">{t('app:admin.invite_col_expires')}</th>
                <th className="py-2 pr-3">{t('app:admin.invite_col_status')}</th>
                <th className="py-2" />
              </tr>
            </thead>
            <tbody className="divide-y divide-line">
              {invites.map((inv) => {
                const expired = inv.expiresAt ? new Date(inv.expiresAt) < new Date() : false;
                const status = inv.disabled
                  ? t('app:admin.invite_status_disabled')
                  : expired
                    ? t('app:admin.invite_status_expired')
                    : t('app:admin.invite_status_active');
                const statusColor = inv.disabled
                  ? 'text-rose-600 dark:text-rose-300'
                  : expired
                    ? 'text-amber-600 dark:text-amber-300'
                    : 'text-emerald-600 dark:text-emerald-300';
                const usesText = inv.usesLimit
                  ? inv.usesCount + '/' + inv.usesLimit
                  : inv.usesCount + '/∞';
                const expiresText = inv.expiresAt
                  ? new Date(inv.expiresAt).toLocaleDateString()
                  : t('app:admin.invite_expires_never');
                return (
                  <tr key={inv.code} className="py-2">
                    <td className="py-2 pr-3 font-mono text-xs text-fg">{inv.code}</td>
                    <td className="py-2 pr-3 text-xs text-fg-muted">{usesText}</td>
                    <td className="py-2 pr-3 text-xs text-fg-muted">{expiresText}</td>
                    <td className={'py-2 pr-3 text-xs font-medium ' + statusColor}>{status}</td>
                    <td className="py-2 text-right">
                      <div className="inline-flex gap-1">
                        <IconButton
                          label={
                            copiedCode === inv.code
                              ? t('app:admin.invites_copied')
                              : t('app:admin.invites_copy')
                          }
                          onClick={() => void handleCopy(inv.code)}
                        >
                          <CopyIcon className="h-3.5 w-3.5" />
                        </IconButton>
                        <button
                          type="button"
                          onClick={() => void handleToggle(inv.code, inv.disabled)}
                          className="rounded-md border border-line bg-surface-3 px-2 py-1 text-[11px] font-medium text-fg transition hover:brightness-95"
                        >
                          {inv.disabled ? t('app:admin.invites_enable') : t('app:admin.invites_disable')}
                        </button>
                        <IconButton
                          label={t('app:admin.invites_delete')}
                          tone="danger"
                          onClick={() => void handleDelete(inv.code)}
                        >
                          <TrashIcon className="h-3.5 w-3.5" />
                        </IconButton>
                      </div>
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>
      )}
    </Section>
  );
}

// --- Users -----------------------------------------------------------------

function UsersSection({ users, onRefresh }: { users: AdminProfileRow[]; onRefresh: () => Promise<void> }) {
  const { t } = useTranslation(['app']);

  async function toggle(userId: string, flag: AdminProfileFlag, value: boolean) {
    try {
      await setUserFlag(supabase, userId, flag, value);
      await onRefresh();
    } catch (err: unknown) {
      console.error(err);
    }
  }

  return (
    <Section title={t('app:admin.users_title')}>
      {users.length === 0 ? (
        <p className="text-sm text-fg-muted">{t('app:admin.users_empty')}</p>
      ) : (
        <ul className="divide-y divide-line">
          {users.map((u) => {
            return (
              <li key={u.userId} className="flex items-center gap-3 py-3">
                <Avatar
                  displayName={u.displayName ?? u.username}
                  className="h-9 w-9 text-sm"
                />
                <div className="min-w-0 flex-1">
                  <p className="truncate text-sm font-semibold text-fg">{u.displayName}</p>
                  <p className="truncate text-xs text-fg-muted">@{u.username}</p>
                </div>
                <div className="flex gap-2">
                  <FlagChip
                    label={t('app:admin.users_flag_admin')}
                    active={u.isAdmin}
                    onToggle={(v) => void toggle(u.userId, 'is_admin', v)}
                  />
                  <FlagChip
                    label={t('app:admin.users_flag_blocked_inviting')}
                    active={u.blockedFromInviting}
                    onToggle={(v) => void toggle(u.userId, 'blocked_from_inviting', v)}
                  />
                  <FlagChip
                    label={t('app:admin.users_flag_banned')}
                    tone="danger"
                    active={u.banned}
                    onToggle={(v) => void toggle(u.userId, 'banned', v)}
                  />
                </div>
              </li>
            );
          })}
        </ul>
      )}
    </Section>
  );
}

// --- Bits ------------------------------------------------------------------

function Toggle({
  label,
  hint,
  checked,
  disabled,
  onChange,
}: {
  label: string;
  hint?: string;
  checked: boolean;
  disabled?: boolean;
  onChange: (next: boolean) => void;
}) {
  return (
    <label className="flex cursor-pointer items-start justify-between gap-4">
      <span className="min-w-0 flex-1">
        <span className="block text-sm text-fg">{label}</span>
        {hint && <span className="mt-1 block text-xs text-fg-muted">{hint}</span>}
      </span>
      <span className="relative mt-0.5 inline-flex h-6 w-11 shrink-0">
        <input
          type="checkbox"
          checked={checked}
          disabled={disabled}
          onChange={(e) => onChange(e.target.checked)}
          className="peer sr-only"
        />
        <span className="inline-block h-6 w-11 rounded-full bg-surface transition peer-checked:bg-accent peer-disabled:opacity-50" />
        <span className="absolute left-0.5 top-0.5 h-5 w-5 rounded-full bg-white shadow transition peer-checked:translate-x-5" />
      </span>
    </label>
  );
}

function IconButton({
  label,
  children,
  onClick,
  tone,
}: {
  label: string;
  children: React.ReactNode;
  onClick: () => void;
  tone?: 'danger';
}) {
  return (
    <button
      type="button"
      onClick={onClick}
      aria-label={label}
      title={label}
      className={
        'flex h-7 w-7 cursor-pointer items-center justify-center rounded-md border transition focus:outline-none focus-visible:ring-2 ' +
        (tone === 'danger'
          ? 'border-rose-500/40 bg-rose-500/10 text-rose-600 hover:bg-rose-500/20 focus-visible:ring-rose-400/40 dark:text-rose-300'
          : 'border-line bg-surface-3 text-fg hover:brightness-95 focus-visible:ring-accent/40')
      }
    >
      {children}
    </button>
  );
}

function FlagChip({
  label,
  active,
  onToggle,
  tone,
}: {
  label: string;
  active: boolean;
  onToggle: (next: boolean) => void;
  tone?: 'danger';
}) {
  const activeClass =
    tone === 'danger'
      ? 'border-rose-500/40 bg-rose-500/20 text-rose-700 dark:text-rose-100'
      : 'border-accent/40 bg-accent/20 text-accent';
  return (
    <button
      type="button"
      onClick={() => onToggle(!active)}
      className={
        'cursor-pointer rounded-full border px-2.5 py-0.5 text-[11px] font-medium transition focus:outline-none focus-visible:ring-2 focus-visible:ring-accent/40 ' +
        (active ? activeClass : 'border-line bg-surface-3 text-fg-muted hover:brightness-95')
      }
    >
      {label}
    </button>
  );
}
