import { createContext, useContext, useState, useEffect, useCallback, type ReactNode } from 'react';
import { fetchMe, loginApi, logoutApi, LoginError, type BackendUser } from '@/services/authApi';
import { useMenuStore } from '@stores/menuStore';

/*
 * SFR-01: 시스템 로그인 및 권한 관리
 * - 백엔드 JWT 쿠키 기반 인증
 * - 트리 기반 RBAC (백엔드의 auth_perm_tree + auth_perm)
 * - 다중 역할 + 부모 fallback (예: detection:gear-detection 미존재 시 detection 검사)
 * - 세션 타임아웃: 30분 미사용 시 자동 로그아웃
 * - 로그인 이력 + 감사로그는 백엔드 DB(kcgaidb)에 기록
 */

// ─── RBAC 역할 정의 ─────────────────────
export type UserRole = 'ADMIN' | 'OPERATOR' | 'ANALYST' | 'FIELD' | 'VIEWER';

export interface AuthUser {
  id: string;
  /** 로그인 ID */
  account: string;
  name: string;
  rank: string;
  org: string;
  /** 다중 역할 (백엔드는 배열 반환) */
  roles: UserRole[];
  /** 1차 역할 (기존 코드 호환) */
  role: UserRole;
  /** 권한 트리: rsrcCd → operations[] */
  permissions: Record<string, string[]>;
  authMethod: 'password' | 'gpki' | 'sso';
  loginAt: string;
}

// ─── 세션 타임아웃 (30분) ──────────────────
const SESSION_TIMEOUT = 30 * 60 * 1000;

interface AuthContextType {
  user: AuthUser | null;
  loading: boolean;
  /** ID/PW 로그인 (백엔드 호출) */
  login: (account: string, password: string) => Promise<void>;
  logout: () => Promise<void>;
  /** 경로 기반 접근 가능 여부 (메뉴/라우트 가드용) */
  hasAccess: (path: string) => boolean;
  /** 트리 기반 권한 체크 (resource + operation) */
  hasPermission: (resource: string, operation?: string) => boolean;
  sessionRemaining: number;
}

const AuthContext = createContext<AuthContextType | null>(null);

function backendToAuthUser(b: BackendUser): AuthUser {
  const primaryRole = (b.roles[0] ?? 'VIEWER') as UserRole;
  return {
    id: b.id,
    account: b.account,
    name: b.name,
    rank: b.rank ?? '',
    org: '',  // 향후 백엔드에서 org_sn/org_nm 추가 시 채움
    roles: b.roles as UserRole[],
    role: primaryRole,
    permissions: b.permissions,
    authMethod: (b.authProvider?.toLowerCase() as AuthUser['authMethod']) ?? 'password',
    loginAt: new Date().toISOString().replace('T', ' ').slice(0, 19),
  };
}

/**
 * 트리 기반 권한 체크 (부모 fallback 지원).
 * "detection:gear-detection"이 직접 등록되지 않았으면 "detection" 부모를 검사.
 */
function checkPermission(perms: Record<string, string[]>, resource: string, operation: string): boolean {
  const ops = perms[resource];
  if (ops && ops.includes(operation)) return true;
  // 부모 fallback
  const colonIdx = resource.indexOf(':');
  if (colonIdx > 0) {
    const parent = resource.substring(0, colonIdx);
    const parentOps = perms[parent];
    return !!parentOps && parentOps.includes(operation);
  }
  return false;
}

export function AuthProvider({ children }: { children: ReactNode }) {
  const [user, setUser] = useState<AuthUser | null>(null);
  const [loading, setLoading] = useState(true);
  const [lastActivity, setLastActivity] = useState(Date.now());
  const [sessionRemaining, setSessionRemaining] = useState(SESSION_TIMEOUT / 1000);

  // 초기 세션 복원: /api/auth/me 호출
  useEffect(() => {
    let alive = true;
    fetchMe()
      .then((b) => {
        if (alive && b) {
          setUser(backendToAuthUser(b));
          if (b.menuConfig) useMenuStore.getState().setMenuConfig(b.menuConfig);
        }
      })
      .finally(() => {
        if (alive) setLoading(false);
      });
    return () => {
      alive = false;
    };
  }, []);

  // 사용자 활동 감지 → 세션 갱신
  const resetActivity = useCallback(() => {
    setLastActivity(Date.now());
  }, []);

  useEffect(() => {
    if (!user) return;
    const events = ['mousedown', 'keydown', 'scroll', 'touchstart'];
    events.forEach((e) => window.addEventListener(e, resetActivity));
    return () => events.forEach((e) => window.removeEventListener(e, resetActivity));
  }, [user, resetActivity]);

  // 세션 타임아웃 체크
  useEffect(() => {
    if (!user) return;
    const interval = setInterval(() => {
      const elapsed = Date.now() - lastActivity;
      const remaining = Math.max(0, Math.floor((SESSION_TIMEOUT - elapsed) / 1000));
      setSessionRemaining(remaining);

      if (elapsed >= SESSION_TIMEOUT) {
        logoutApi().catch(() => undefined);
        setUser(null);
      }
    }, 1000);
    return () => clearInterval(interval);
  }, [user, lastActivity]);

  const login = useCallback(async (account: string, password: string) => {
    try {
      const b = await loginApi(account, password);
      setUser(backendToAuthUser(b));
      if (b.menuConfig) useMenuStore.getState().setMenuConfig(b.menuConfig);
      setLastActivity(Date.now());
    } catch (e) {
      if (e instanceof LoginError) throw e;
      throw new LoginError('NETWORK_ERROR');
    }
  }, []);

  const logout = useCallback(async () => {
    try {
      await logoutApi();
    } finally {
      setUser(null);
      useMenuStore.getState().clear();
    }
  }, []);

  const hasPermission = useCallback(
    (resource: string, operation: string = 'READ') => {
      if (!user) return false;
      return checkPermission(user.permissions, resource, operation);
    },
    [user],
  );

  const hasAccess = useCallback(
    (path: string) => {
      if (!user) return false;
      // DB menu_config 기반 longest-match (PATH_TO_RESOURCE 대체)
      const resource = useMenuStore.getState().getResourceForPath(path);
      if (!resource) return true;
      return hasPermission(resource, 'READ');
    },
    [user, hasPermission],
  );

  return (
    <AuthContext.Provider value={{ user, loading, login, logout, hasAccess, hasPermission, sessionRemaining }}>
      {children}
    </AuthContext.Provider>
  );
}

export function useAuth() {
  const ctx = useContext(AuthContext);
  if (!ctx) throw new Error('useAuth must be inside AuthProvider');
  return ctx;
}
