import { useMemo, useState } from 'react'
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
import { toast } from 'sonner'
import { Search, Shield, Check, Users, KeyRound, BarChart3 } from 'lucide-react'
import { PageHeader } from '@/components/PageHeader'
import { Input } from '@/components/ui/Input'
import { api } from '@/lib/api'
import { getErrorMessage } from '@/lib/apiError'
import { cn } from '@/lib/cn'
import type { MenuItem, Permission, Role } from '@/types/menu'

type CrudKey = 'canRead' | 'canCreate' | 'canUpdate' | 'canDelete'
const CRUD_COLS: { key: CrudKey; label: string; short: string; tone: string }[] = [
  { key: 'canRead',   label: 'Xem', short: 'R', tone: 'bg-slate-100 text-slate-700' },
  { key: 'canCreate', label: 'Tạo', short: 'C', tone: 'bg-emerald-100 text-emerald-700' },
  { key: 'canUpdate', label: 'Sửa', short: 'U', tone: 'bg-amber-100 text-amber-700' },
  { key: 'canDelete', label: 'Xóa', short: 'D', tone: 'bg-red-100 text-red-700' },
]

export function PermissionsPage() {
  const qc = useQueryClient()
  const [roleId, setRoleId] = useState<string>('')
  const [search, setSearch] = useState('')

  const roles = useQuery({
    queryKey: ['roles'],
    queryFn: async () => (await api.get<Role[]>('/roles')).data,
  })

  const menus = useQuery({
    queryKey: ['menus', 'all'],
    queryFn: async () => (await api.get<MenuItem[]>('/menus')).data,
  })

  const perms = useQuery({
    queryKey: ['permissions', roleId],
    queryFn: async () => (await api.get<Permission[]>(`/permissions/by-role/${roleId}`)).data,
    enabled: !!roleId,
  })

  const upsert = useMutation({
    mutationFn: async (p: { menuKey: string; canRead: boolean; canCreate: boolean; canUpdate: boolean; canDelete: boolean }) => {
      await api.put('/permissions', { roleId, ...p })
    },
    onSuccess: () => qc.invalidateQueries({ queryKey: ['permissions', roleId] }),
    onError: err => toast.error(getErrorMessage(err)),
  })

  const permMap = useMemo(() => {
    const map = new Map<string, Permission>()
    for (const p of perms.data ?? []) map.set(p.menuKey, p)
    return map
  }, [perms.data])

  const filteredMenus = useMemo(() => {
    const all = menus.data ?? []
    if (!search.trim()) return all
    const q = search.toLowerCase()
    return all.filter(m => m.label.toLowerCase().includes(q) || m.key.toLowerCase().includes(q))
  }, [menus.data, search])

  const stats = useMemo(() => {
    const totalMenus = menus.data?.length ?? 0
    const total = totalMenus * 4
    const breakdown = { canRead: 0, canCreate: 0, canUpdate: 0, canDelete: 0 }
    let granted = 0
    for (const m of menus.data ?? []) {
      const p = permMap.get(m.key)
      if (!p) continue
      if (p.canRead) { granted++; breakdown.canRead++ }
      if (p.canCreate) { granted++; breakdown.canCreate++ }
      if (p.canUpdate) { granted++; breakdown.canUpdate++ }
      if (p.canDelete) { granted++; breakdown.canDelete++ }
    }
    return { granted, total, totalMenus, breakdown }
  }, [menus.data, permMap])

  function currentFlags(menuKey: string) {
    const p = permMap.get(menuKey)
    return {
      canRead: p?.canRead ?? false,
      canCreate: p?.canCreate ?? false,
      canUpdate: p?.canUpdate ?? false,
      canDelete: p?.canDelete ?? false,
    }
  }

  function toggle(menuKey: string, field: CrudKey) {
    const flags = currentFlags(menuKey)
    upsert.mutate({ menuKey, ...flags, [field]: !flags[field] })
  }

  function columnAllChecked(field: CrudKey) {
    return filteredMenus.length > 0 && filteredMenus.every(m => currentFlags(m.key)[field])
  }

  function toggleColumn(field: CrudKey) {
    const allChecked = columnAllChecked(field)
    const nextVal = !allChecked
    for (const m of filteredMenus) {
      const flags = currentFlags(m.key)
      if (flags[field] !== nextVal) {
        upsert.mutate({ menuKey: m.key, ...flags, [field]: nextVal })
      }
    }
  }

  const selectedRole = roles.data?.find(r => r.id === roleId)

  return (
    <div className="p-6">
      <PageHeader
        title="Ma trận phân quyền"
        description="3 panel — chọn vai trò (Panel 1), tick quyền CRUD cho từng menu (Panel 2), xem tổng quan (Panel 3). Thay đổi lưu tự động."
      />

      {/* 3-column layout. Heights match so panels align. */}
      <div className="grid grid-cols-1 gap-4 lg:grid-cols-[280px_1fr_300px]">
        {/* ===== Panel 1: Role list ===== */}
        <section className="flex flex-col rounded-xl border border-slate-200 bg-white shadow-sm">
          <header className="flex items-center gap-2 border-b border-slate-100 px-4 py-3">
            <Users className="h-4 w-4 text-brand-600" />
            <h2 className="text-sm font-semibold text-slate-700">1. Vai trò</h2>
            <span className="ml-auto text-[11px] text-slate-400">{roles.data?.length ?? 0}</span>
          </header>
          <div className="flex-1 overflow-y-auto p-2">
            {roles.isLoading && <div className="p-4 text-xs text-slate-400">Đang tải…</div>}
            {roles.data?.map(r => (
              <button
                key={r.id}
                onClick={() => setRoleId(r.id)}
                className={cn(
                  'flex w-full items-center justify-between gap-2 rounded-md px-3 py-2 text-left transition',
                  roleId === r.id
                    ? 'bg-brand-50 text-brand-700 font-medium ring-1 ring-brand-200'
                    : 'text-slate-600 hover:bg-slate-50',
                )}
                title={r.description ?? r.name}
              >
                <span className="min-w-0 flex-1">
                  <span className="block text-sm font-semibold">{r.shortName ?? r.name}</span>
                  <span className="block truncate text-[11px] font-normal text-slate-500">
                    {r.description ?? r.name}
                  </span>
                </span>
                {roleId === r.id && <Check className="h-3.5 w-3.5 shrink-0" />}
              </button>
            ))}
          </div>
        </section>

        {/* ===== Panel 2: Menu × CRUD matrix ===== */}
        <section className="flex flex-col rounded-xl border border-slate-200 bg-white shadow-sm">
          <header className="flex items-center gap-2 border-b border-slate-100 px-4 py-3">
            <KeyRound className="h-4 w-4 text-brand-600" />
            <h2 className="text-sm font-semibold text-slate-700">2. Quyền theo menu</h2>
            {selectedRole && (
              <span className="rounded-full bg-brand-50 px-2 py-0.5 text-[10px] font-medium text-brand-700" title={selectedRole.description ?? ''}>
                {selectedRole.shortName ?? selectedRole.name}
              </span>
            )}
            <div className="ml-auto w-56">
              <div className="relative">
                <Search className="pointer-events-none absolute left-2 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-slate-400" />
                <Input
                  placeholder="Tìm menu…"
                  value={search}
                  onChange={e => setSearch(e.target.value)}
                  className="h-8 pl-7 text-xs"
                  disabled={!roleId}
                />
              </div>
            </div>
          </header>

          {!roleId ? (
            <div className="flex flex-1 items-center justify-center p-8 text-center text-sm text-slate-400">
              <div>
                <Shield className="mx-auto mb-2 h-8 w-8 text-slate-300" />
                <div>Chọn vai trò ở panel 1 để bắt đầu</div>
              </div>
            </div>
          ) : (
            <div className="flex-1 overflow-auto">
              <table className="w-full text-sm">
                <thead className="sticky top-0 bg-slate-50/80 text-slate-600 backdrop-blur">
                  <tr className="border-b border-slate-200">
                    <th className="px-4 py-2 text-left text-[11px] font-semibold uppercase tracking-wider">
                      Menu
                      {search && (
                        <span className="ml-2 font-normal normal-case text-slate-400">
                          ({filteredMenus.length} kết quả)
                        </span>
                      )}
                    </th>
                    {CRUD_COLS.map(c => {
                      const allChecked = columnAllChecked(c.key)
                      return (
                        <th key={c.key} className="w-20 px-2 py-2 text-center">
                          <div className="flex flex-col items-center gap-1">
                            <span className="text-[11px] font-semibold uppercase tracking-wider">{c.label}</span>
                            <button
                              onClick={() => toggleColumn(c.key)}
                              title={allChecked ? 'Bỏ tick toàn cột' : 'Tick toàn cột'}
                              disabled={upsert.isPending || filteredMenus.length === 0}
                              className={cn(
                                'flex h-5 w-5 items-center justify-center rounded border transition',
                                allChecked
                                  ? 'border-brand-600 bg-brand-600 text-white'
                                  : 'border-slate-300 bg-white text-slate-400 hover:border-brand-500',
                              )}
                            >
                              {allChecked && <Check className="h-3 w-3" />}
                            </button>
                          </div>
                        </th>
                      )
                    })}
                  </tr>
                </thead>
                <tbody>
                  {filteredMenus.length === 0 && (
                    <tr>
                      <td colSpan={5} className="px-4 py-10 text-center text-xs text-slate-400">
                        Không có menu khớp với từ khóa.
                      </td>
                    </tr>
                  )}
                  {filteredMenus.map(m => {
                    const flags = currentFlags(m.key)
                    const depth = m.parentKey ? 1 : 0
                    return (
                      <tr key={m.key} className="border-t border-slate-100 hover:bg-brand-50/30">
                        <td className="px-4 py-2" style={{ paddingLeft: `${1 + depth * 1.25}rem` }}>
                          <div className="font-medium text-slate-800">{m.label}</div>
                          <div className="font-mono text-[10px] text-slate-400">{m.key}</div>
                        </td>
                        {CRUD_COLS.map(c => (
                          <td key={c.key} className="px-2 py-2 text-center">
                            <input
                              type="checkbox"
                              className="h-4 w-4 cursor-pointer accent-brand-600"
                              checked={flags[c.key]}
                              disabled={upsert.isPending}
                              onChange={() => toggle(m.key, c.key)}
                            />
                          </td>
                        ))}
                      </tr>
                    )
                  })}
                </tbody>
              </table>
            </div>
          )}
        </section>

        {/* ===== Panel 3: Stats / summary ===== */}
        <section className="flex flex-col rounded-xl border border-slate-200 bg-white shadow-sm">
          <header className="flex items-center gap-2 border-b border-slate-100 px-4 py-3">
            <BarChart3 className="h-4 w-4 text-brand-600" />
            <h2 className="text-sm font-semibold text-slate-700">3. Tổng quan</h2>
          </header>
          <div className="flex-1 space-y-4 overflow-y-auto p-4">
            {!roleId ? (
              <div className="text-center text-xs text-slate-400">Chưa có vai trò được chọn.</div>
            ) : (
              <>
                <div>
                  <div className="text-[10px] font-semibold uppercase tracking-wider text-slate-400">Vai trò</div>
                  <div className="mt-1 flex items-center gap-2 text-sm font-semibold text-slate-800">
                    <Shield className="h-3.5 w-3.5 text-brand-600" />
                    {selectedRole?.name}
                  </div>
                </div>

                <div>
                  <div className="text-[10px] font-semibold uppercase tracking-wider text-slate-400">Quyền đã cấp</div>
                  <div className="mt-1 flex items-baseline gap-1">
                    <span className="text-3xl font-bold text-brand-600 tabular-nums">{stats.granted}</span>
                    <span className="text-xs text-slate-400">/ {stats.total}</span>
                  </div>
                  <div className="mt-1.5 h-1.5 overflow-hidden rounded-full bg-slate-100">
                    <div
                      className="h-full rounded-full bg-brand-500 transition-all"
                      style={{ width: `${stats.total > 0 ? (stats.granted / stats.total) * 100 : 0}%` }}
                    />
                  </div>
                </div>

                <div className="space-y-1.5">
                  <div className="text-[10px] font-semibold uppercase tracking-wider text-slate-400">Chi tiết CRUD</div>
                  {CRUD_COLS.map(c => (
                    <div key={c.key} className="flex items-center justify-between rounded-md border border-slate-100 px-2.5 py-1.5">
                      <span className={cn('rounded px-1.5 py-0.5 text-[11px] font-medium', c.tone)}>
                        {c.label}
                      </span>
                      <span className="font-mono text-xs text-slate-600">
                        {stats.breakdown[c.key]}
                        <span className="text-slate-400"> / {stats.totalMenus}</span>
                      </span>
                    </div>
                  ))}
                </div>

                <div className="rounded-md border border-slate-100 bg-slate-50 p-3 text-[11px] leading-relaxed text-slate-500">
                  <strong>Tip:</strong> click header ô tick ở panel 2 để tick/untick toàn cột. Thay đổi tự lưu.
                </div>
              </>
            )}
          </div>
        </section>
      </div>
    </div>
  )
}
