import { useState, useEffect, useCallback } from 'react';
import {
  fetchRoles,
  fetchPermTree,
  updatePermissionsApi,
  createRoleApi,
  deleteRoleApi,
  updateRoleApi,
  updateRoleDefaultApi,
  type RoleWithPermissions,
  type PermTreeNode,
} from '@common/services/authApi';
import { RolePermTab } from './contents/RolePermTab';
import { UserPermTab } from './contents/UserPermTab';
/* eslint-disable react-refresh/only-export-components */

// ─── 오퍼레이션 코드 ─────────────────────────────────
export const OPER_CODES = ['READ', 'CREATE', 'UPDATE', 'DELETE'] as const;
export type OperCode = (typeof OPER_CODES)[number];
export const OPER_LABELS: Record<OperCode, string> = { READ: 'R', CREATE: 'C', UPDATE: 'U', DELETE: 'D' };
export const OPER_FULL_LABELS: Record<OperCode, string> = {
  READ: '조회',
  CREATE: '생성',
  UPDATE: '수정',
  DELETE: '삭제',
};

// ─── 권한 상태 타입 ─────────────────────────────────────
export type PermState = 'explicit-granted' | 'inherited-granted' | 'explicit-denied' | 'forced-denied';

// ─── 키 유틸 ──────────────────────────────────────────
export function makeKey(rsrc: string, oper: string): string {
  return `${rsrc}::${oper}`;
}

// ─── 유틸: 플랫 노드 목록 추출 (트리 DFS) ─────────────
export function flattenTree(nodes: PermTreeNode[]): PermTreeNode[] {
  const result: PermTreeNode[] = [];
  function walk(list: PermTreeNode[]) {
    for (const n of list) {
      result.push(n);
      if (n.children.length > 0) walk(n.children);
    }
  }
  walk(nodes);
  return result;
}

// ─── 유틸: 권한 상태 계산 (오퍼레이션별) ──────────────
function resolvePermStateForOper(
  code: string,
  parentCode: string | null,
  operCd: string,
  explicitPerms: Map<string, boolean>,
  cache: Map<string, PermState>,
): PermState {
  const key = makeKey(code, operCd);
  const cached = cache.get(key);
  if (cached) return cached;

  const explicit = explicitPerms.get(key);

  if (parentCode === null) {
    const state: PermState =
      explicit === true
        ? 'explicit-granted'
        : explicit === false
          ? 'explicit-denied'
          : 'explicit-denied';
    cache.set(key, state);
    return state;
  }

  // 부모 READ 확인 (접근 게이트)
  const parentReadKey = makeKey(parentCode, 'READ');
  const parentReadState = cache.get(parentReadKey);
  if (parentReadState === 'explicit-denied' || parentReadState === 'forced-denied') {
    cache.set(key, 'forced-denied');
    return 'forced-denied';
  }

  if (explicit === true) {
    cache.set(key, 'explicit-granted');
    return 'explicit-granted';
  }
  if (explicit === false) {
    cache.set(key, 'explicit-denied');
    return 'explicit-denied';
  }

  // 부모의 같은 오퍼레이션 상속
  const parentOperKey = makeKey(parentCode, operCd);
  const parentOperState = cache.get(parentOperKey);
  if (parentOperState === 'explicit-granted' || parentOperState === 'inherited-granted') {
    cache.set(key, 'inherited-granted');
    return 'inherited-granted';
  }
  if (parentOperState === 'forced-denied') {
    cache.set(key, 'forced-denied');
    return 'forced-denied';
  }

  cache.set(key, 'explicit-denied');
  return 'explicit-denied';
}

export function buildEffectiveStates(
  flatNodes: PermTreeNode[],
  explicitPerms: Map<string, boolean>,
): Map<string, PermState> {
  const cache = new Map<string, PermState>();
  for (const node of flatNodes) {
    // READ 먼저 (CUD는 READ에 의존)
    resolvePermStateForOper(node.code, node.parentCode, 'READ', explicitPerms, cache);
    for (const oper of OPER_CODES) {
      if (oper === 'READ') continue;
      resolvePermStateForOper(node.code, node.parentCode, oper, explicitPerms, cache);
    }
  }
  return cache;
}

type ActiveTab = 'role' | 'user';

function PermissionsPanel() {
  const [activeTab, setActiveTab] = useState<ActiveTab>('role');
  const [roles, setRoles] = useState<RoleWithPermissions[]>([]);
  const [permTree, setPermTree] = useState<PermTreeNode[]>([]);
  const [loading, setLoading] = useState(true);
  const [saving, setSaving] = useState(false);
  const [saveError, setSaveError] = useState<string | null>(null);
  const [dirty, setDirty] = useState(false);
  const [showCreateForm, setShowCreateForm] = useState(false);
  const [newRoleCode, setNewRoleCode] = useState('');
  const [newRoleName, setNewRoleName] = useState('');
  const [newRoleDesc, setNewRoleDesc] = useState('');
  const [creating, setCreating] = useState(false);
  const [createError, setCreateError] = useState('');
  const [editingRoleSn, setEditingRoleSn] = useState<number | null>(null);
  const [editRoleName, setEditRoleName] = useState('');
  const [expanded, setExpanded] = useState<Set<string>>(new Set());
  const [selectedRoleSn, setSelectedRoleSn] = useState<number | null>(null);

  // 역할별 명시적 권한: Map<roleSn, Map<"rsrc::oper", boolean>>
  const [rolePerms, setRolePerms] = useState<Map<number, Map<string, boolean>>>(new Map());

  const loadData = useCallback(async () => {
    setLoading(true);
    try {
      const [rolesData, treeData] = await Promise.all([fetchRoles(), fetchPermTree()]);
      setRoles(rolesData);
      setPermTree(treeData);

      // 명시적 권한 맵 초기화 (rsrc::oper 키 형식)
      const permsMap = new Map<number, Map<string, boolean>>();
      for (const role of rolesData) {
        const roleMap = new Map<string, boolean>();
        for (const p of role.permissions) {
          roleMap.set(makeKey(p.resourceCode, p.operationCode), p.granted);
        }
        permsMap.set(role.sn, roleMap);
      }
      setRolePerms(permsMap);

      // 최상위 노드 기본 펼침
      setExpanded(new Set(treeData.map((n) => n.code)));
      // 첫 번째 역할 선택
      if (rolesData.length > 0 && !selectedRoleSn) {
        setSelectedRoleSn(rolesData[0].sn);
      }
      setDirty(false);
    } catch (err) {
      console.error('권한 데이터 조회 실패:', err);
    } finally {
      setLoading(false);
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps -- 초기 마운트 시 1회만 실행
  }, []);

  useEffect(() => {
    loadData();
  }, [loadData]);

  // 플랫 노드 목록
  const flatNodes = flattenTree(permTree);

  const handleToggleExpand = useCallback((code: string) => {
    setExpanded((prev) => {
      const next = new Set(prev);
      if (next.has(code)) next.delete(code);
      else next.add(code);
      return next;
    });
  }, []);

  const handleTogglePerm = useCallback(
    (code: string, oper: OperCode, currentState: PermState) => {
      if (!selectedRoleSn) return;

      setRolePerms((prev) => {
        const next = new Map(prev);
        const roleMap = new Map(next.get(selectedRoleSn) ?? new Map());

        const key = makeKey(code, oper);
        const node = flatNodes.find((n) => n.code === code);
        const isRoot = node ? node.parentCode === null : false;

        switch (currentState) {
          case 'explicit-granted':
            roleMap.set(key, false);
            break;
          case 'inherited-granted':
            roleMap.set(key, false);
            break;
          case 'explicit-denied':
            if (isRoot) {
              roleMap.set(key, true);
            } else {
              roleMap.delete(key);
            }
            break;
          default:
            return prev;
        }

        next.set(selectedRoleSn, roleMap);
        return next;
      });
      setDirty(true);
    },
    [selectedRoleSn, flatNodes],
  );

  const handleSave = async () => {
    setSaving(true);
    setSaveError(null);
    try {
      for (const role of roles) {
        const perms = rolePerms.get(role.sn);
        if (!perms) continue;

        const permsList: Array<{ resourceCode: string; operationCode: string; granted: boolean }> =
          [];
        for (const [key, granted] of perms) {
          const sepIdx = key.indexOf('::');
          permsList.push({
            resourceCode: key.substring(0, sepIdx),
            operationCode: key.substring(sepIdx + 2),
            granted,
          });
        }
        await updatePermissionsApi(role.sn, permsList);
      }
      setDirty(false);
    } catch (err) {
      console.error('권한 저장 실패:', err);
      setSaveError('권한 저장에 실패했습니다. 다시 시도해주세요.');
    } finally {
      setSaving(false);
    }
  };

  const handleCreateRole = async () => {
    setCreating(true);
    setCreateError('');
    try {
      await createRoleApi({
        code: newRoleCode,
        name: newRoleName,
        description: newRoleDesc || undefined,
      });
      await loadData();
      setShowCreateForm(false);
      setNewRoleCode('');
      setNewRoleName('');
      setNewRoleDesc('');
    } catch (err) {
      const message = err instanceof Error ? err.message : '역할 생성에 실패했습니다.';
      setCreateError(message);
    } finally {
      setCreating(false);
    }
  };

  const handleDeleteRole = async (roleSn: number, roleName: string) => {
    if (
      !window.confirm(
        `"${roleName}" 역할을 삭제하시겠습니까?\n이 역할을 가진 모든 사용자에서 해당 역할이 제거됩니다.`,
      )
    ) {
      return;
    }
    try {
      await deleteRoleApi(roleSn);
      if (selectedRoleSn === roleSn) setSelectedRoleSn(null);
      await loadData();
    } catch (err) {
      console.error('역할 삭제 실패:', err);
    }
  };

  const handleStartEditName = (role: RoleWithPermissions) => {
    setEditingRoleSn(role.sn);
    setEditRoleName(role.name);
  };

  const handleSaveRoleName = async (roleSn: number) => {
    if (!editRoleName.trim()) return;
    try {
      await updateRoleApi(roleSn, { name: editRoleName.trim() });
      setRoles((prev) =>
        prev.map((r) => (r.sn === roleSn ? { ...r, name: editRoleName.trim() } : r)),
      );
      setEditingRoleSn(null);
    } catch (err) {
      console.error('역할 이름 수정 실패:', err);
    }
  };

  const toggleDefault = async (roleSn: number) => {
    const role = roles.find((r) => r.sn === roleSn);
    if (!role) return;
    const newValue = !role.isDefault;
    try {
      await updateRoleDefaultApi(roleSn, newValue);
      setRoles((prev) => prev.map((r) => (r.sn === roleSn ? { ...r, isDefault: newValue } : r)));
    } catch (err) {
      console.error('기본 역할 변경 실패:', err);
    }
  };

  if (loading) {
    return (
      <div className="flex items-center justify-center h-32 text-fg-disabled text-body-2 font-korean">
        불러오는 중...
      </div>
    );
  }

  return (
    <div className="flex flex-col h-full">
      {/* 헤더 */}
      <div
        className="flex items-center justify-between px-4 py-2.5 border-b border-stroke"
        style={{ flexShrink: 0 }}
      >
        <div>
          <h1 className="text-body-2 font-bold text-fg font-korean">권한 관리</h1>
          <p className="text-caption text-fg-disabled mt-0.5 font-korean">
            역할별 리소스 × CRUD 권한 설정
          </p>
        </div>
        {/* 탭 전환 */}
        <div className="flex items-center gap-1 p-1 bg-bg-elevated rounded-lg border border-stroke">
          <button
            onClick={() => setActiveTab('role')}
            className={`px-4 py-1.5 text-caption font-semibold rounded-md transition-all font-korean ${
              activeTab === 'role'
                ? 'bg-color-accent text-bg-0 shadow-[0_0_8px_rgba(6,182,212,0.25)]'
                : 'text-fg-disabled hover:text-fg-sub'
            }`}
          >
            그룹별
          </button>
          <button
            onClick={() => setActiveTab('user')}
            className={`px-4 py-1.5 text-caption font-semibold rounded-md transition-all font-korean ${
              activeTab === 'user'
                ? 'bg-color-accent text-bg-0 shadow-[0_0_8px_rgba(6,182,212,0.25)]'
                : 'text-fg-disabled hover:text-fg-sub'
            }`}
          >
            사용자별
          </button>
        </div>
      </div>

      {activeTab === 'role' ? (
        <RolePermTab
          roles={roles}
          permTree={permTree}
          rolePerms={rolePerms}
          setRolePerms={setRolePerms}
          selectedRoleSn={selectedRoleSn}
          setSelectedRoleSn={setSelectedRoleSn}
          dirty={dirty}
          saving={saving}
          saveError={saveError}
          handleSave={handleSave}
          handleToggleExpand={handleToggleExpand}
          handleTogglePerm={handleTogglePerm}
          expanded={expanded}
          flatNodes={flatNodes}
          editingRoleSn={editingRoleSn}
          editRoleName={editRoleName}
          setEditRoleName={setEditRoleName}
          handleStartEditName={handleStartEditName}
          handleSaveRoleName={handleSaveRoleName}
          setEditingRoleSn={setEditingRoleSn}
          toggleDefault={toggleDefault}
          handleDeleteRole={handleDeleteRole}
          showCreateForm={showCreateForm}
          setShowCreateForm={setShowCreateForm}
          setCreateError={setCreateError}
          newRoleCode={newRoleCode}
          setNewRoleCode={setNewRoleCode}
          newRoleName={newRoleName}
          setNewRoleName={setNewRoleName}
          newRoleDesc={newRoleDesc}
          setNewRoleDesc={setNewRoleDesc}
          creating={creating}
          createError={createError}
          handleCreateRole={handleCreateRole}
        />
      ) : (
        <UserPermTab roles={roles} permTree={permTree} rolePerms={rolePerms} />
      )}
    </div>
  );
}

export default PermissionsPanel;
