'use client';

import { useState, useMemo, useCallback, useEffect, useRef } from 'react';
import { invalidateDashboard } from '@/lib/dashboard-invalidation';
import { useRouter } from 'next/navigation';
import {
  Clock,
  UserCheck,
  AlertCircle,
  Calendar,
  Plus,
  FileText,
  Search,
} from 'lucide-react';
import type { ExcelColumn } from '@/lib/utils/excel-download';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Checkbox } from '@/components/ui/checkbox';
import { TableRow, TableCell } from '@/components/ui/table';
import { format } from 'date-fns';
import { ko } from 'date-fns/locale';
import {
  UniversalListPage,
  type UniversalListConfig,
  type StatCard,
  type FilterFieldConfig,
  type FilterValues,
} from '@/components/templates/UniversalListPage';
import { DateRangeSelector } from '@/components/molecules/DateRangeSelector';
import { ListMobileCard, InfoField } from '@/components/organisms/MobileCard';
import { AttendanceInfoDialog } from './AttendanceInfoDialog';
import { ReasonInfoDialog } from './ReasonInfoDialog';
import {
  getAttendances,
  getEmployeesForAttendance,
  createAttendance,
  updateAttendance,
} from './actions';
import type {
  AttendanceRecord,
  AttendanceStatus,
  SortOption,
  FilterOption,
  AttendanceFormData,
  ReasonFormData,
  EmployeeOption,
} from './types';
import {
  ATTENDANCE_STATUS_LABELS,
  ATTENDANCE_STATUS_COLORS,
  SORT_OPTIONS,
  FILTER_OPTIONS,
} from './types';
import { isNextRedirectError } from '@/lib/utils/redirect-error';

export function AttendanceManagement() {
  const router = useRouter();

  // 근태 데이터 상태
  const [attendanceRecords, setAttendanceRecords] = useState<AttendanceRecord[]>([]);
  const [employees, setEmployees] = useState<EmployeeOption[]>([]);
  const [isLoading, setIsLoading] = useState(true);
  const isInitialLoadDone = useRef(false);
  const [total, setTotal] = useState(0);

  // 검색 및 필터 상태
  const [searchValue, setSearchValue] = useState('');
  const [activeTab, setActiveTab] = useState<string>('all');
  const [filterOption, setFilterOption] = useState<FilterOption>('all');
  const [sortOption, setSortOption] = useState<SortOption>('dateDesc');
  const [currentPage, setCurrentPage] = useState(1);
  const itemsPerPage = 20;

  // 날짜 범위 상태 (기본값: 오늘)
  const today = new Date();
  const todayStr = format(today, 'yyyy-MM-dd');
  const [startDate, setStartDate] = useState(todayStr);
  const [endDate, setEndDate] = useState(todayStr);

  // 다이얼로그 상태
  const [attendanceDialogOpen, setAttendanceDialogOpen] = useState(false);
  const [attendanceDialogMode, setAttendanceDialogMode] = useState<'create' | 'edit'>('create');
  const [selectedAttendance, setSelectedAttendance] = useState<AttendanceRecord | null>(null);
  const [reasonDialogOpen, setReasonDialogOpen] = useState(false);
  const [selectedItems, setSelectedItems] = useState<Set<string>>(new Set());
  const [isSaving, setIsSaving] = useState(false);

  // 데이터 로드
  useEffect(() => {
    const fetchData = async () => {
      if (!isInitialLoadDone.current) {
        setIsLoading(true);
      }
      try {
        // 사원 목록과 근태 목록 병렬 조회
        const [employeesResult, attendancesResult] = await Promise.all([
          getEmployeesForAttendance(),
          getAttendances({
            per_page: 100,
            date_from: startDate,
            date_to: endDate,
          }),
        ]);

        setEmployees(employeesResult);
        setAttendanceRecords(attendancesResult.data);
        setTotal(attendancesResult.total);
      } catch (error) {
        if (isNextRedirectError(error)) throw error;
        console.error('[AttendanceManagement] fetchData error:', error);
      } finally {
        setIsLoading(false);
        isInitialLoadDone.current = true;
      }
    };
    fetchData();
  }, [startDate, endDate]);

  // 전체 직원 + 근태 기록 병합 (오늘 날짜 조회 시)
  // 근태 기록이 없는 직원은 'notYetIn' 상태로 표시
  const mergedRecords = useMemo(() => {
    // 오늘 하루 조회 시에만 전체 직원 표시
    const isSingleDay = startDate === endDate;

    if (!isSingleDay) {
      // 기간 조회 시에는 기존대로 근태 기록만 표시
      return attendanceRecords;
    }

    // 근태 기록이 있는 직원 ID 집합
    const employeesWithAttendance = new Set(attendanceRecords.map(r => r.employeeId));

    // 근태 기록이 없는 직원들을 'notYetIn' 상태로 추가
    const missingEmployees: AttendanceRecord[] = employees
      .filter(emp => !employeesWithAttendance.has(emp.id))
      .map(emp => ({
        id: `notyet-${emp.id}`,
        employeeId: emp.id,
        employeeName: emp.name,
        department: emp.department,
        position: emp.position,
        rank: emp.rank,
        baseDate: startDate,
        checkIn: null,
        checkOut: null,
        breakTime: null,
        overtimeHours: null,
        workMinutes: null,
        reason: null,
        status: 'notYetIn' as AttendanceStatus,
        remarks: null,
        createdAt: '',
        updatedAt: '',
      }));

    return [...attendanceRecords, ...missingEmployees];
  }, [attendanceRecords, employees, startDate, endDate]);

  // 필터링된 데이터
  const filteredRecords = useMemo(() => {
    let filtered = mergedRecords;

    // 탭(상태) 필터
    if (activeTab !== 'all') {
      filtered = filtered.filter(r => r.status === activeTab);
    }

    // 상단 필터 드롭다운 (탭과 별개)
    if (filterOption !== 'all') {
      filtered = filtered.filter(r => r.status === filterOption);
    }

    // 검색 필터
    if (searchValue) {
      const search = searchValue.toLowerCase();
      filtered = filtered.filter(r =>
        r.employeeName.toLowerCase().includes(search) ||
        r.department.toLowerCase().includes(search)
      );
    }

    // 정렬
    filtered = [...filtered].sort((a, b) => {
      switch (sortOption) {
        case 'dateDesc':
          return new Date(b.baseDate).getTime() - new Date(a.baseDate).getTime();
        case 'dateAsc':
          return new Date(a.baseDate).getTime() - new Date(b.baseDate).getTime();
        case 'rank':
          return a.rank.localeCompare(b.rank, 'ko');
        case 'deptAsc':
          return a.department.localeCompare(b.department, 'ko');
        case 'deptDesc':
          return b.department.localeCompare(a.department, 'ko');
        case 'nameAsc':
          return a.employeeName.localeCompare(b.employeeName, 'ko');
        case 'nameDesc':
          return b.employeeName.localeCompare(a.employeeName, 'ko');
        default:
          return 0;
      }
    });

    return filtered;
  }, [mergedRecords, activeTab, filterOption, searchValue, sortOption]);

  // 페이지네이션된 데이터
  const paginatedData = useMemo(() => {
    const startIndex = (currentPage - 1) * itemsPerPage;
    return filteredRecords.slice(startIndex, startIndex + itemsPerPage);
  }, [filteredRecords, currentPage, itemsPerPage]);

  // 통계 계산 (mergedRecords 기반)
  const stats = useMemo(() => {
    const notYetInCount = mergedRecords.filter(r => r.status === 'notYetIn').length;
    const onTimeCount = mergedRecords.filter(r => r.status === 'onTime').length;
    const lateCount = mergedRecords.filter(r => r.status === 'late').length;
    const absentCount = mergedRecords.filter(r => r.status === 'absent').length;
    const vacationCount = mergedRecords.filter(r => r.status === 'vacation').length;

    return { notYetInCount, onTimeCount, lateCount, absentCount, vacationCount };
  }, [mergedRecords]);

  // StatCards 데이터
  const statCards: StatCard[] = useMemo(() => [
    {
      label: '미출근',
      value: `${stats.notYetInCount}명`,
      icon: AlertCircle,
      iconColor: 'text-gray-500',
    },
    {
      label: '정시 출근',
      value: `${stats.onTimeCount}명`,
      icon: UserCheck,
      iconColor: 'text-green-500',
    },
    {
      label: '지각',
      value: `${stats.lateCount}명`,
      icon: Clock,
      iconColor: 'text-yellow-500',
    },
    {
      label: '휴가',
      value: `${stats.vacationCount}명`,
      icon: Calendar,
      iconColor: 'text-blue-500',
    },
  ], [stats]);

  // 테이블 컬럼 정의
  const tableColumns = useMemo(() => [
    { key: 'no', label: '번호', className: 'w-[60px] text-center' },
    { key: 'department', label: '부서', className: 'min-w-[80px]', sortable: true },
    { key: 'position', label: '직책', className: 'min-w-[100px]', sortable: true },
    { key: 'name', label: '이름', className: 'min-w-[60px]', sortable: true },
    { key: 'rank', label: '직급', className: 'min-w-[60px]', sortable: true },
    { key: 'baseDate', label: '기준일', className: 'min-w-[100px]', sortable: true },
    { key: 'checkIn', label: '출근', className: 'min-w-[60px]', sortable: true },
    { key: 'checkOut', label: '퇴근', className: 'min-w-[60px]', sortable: true },
    { key: 'breakTime', label: '휴게', className: 'min-w-[60px]', sortable: true },
    { key: 'overtime', label: '연장근무', className: 'min-w-[80px]', sortable: true },
    { key: 'reason', label: '사유', className: 'min-w-[80px]', sortable: true },
  ], []);

  // 체크박스 토글
  const toggleSelection = useCallback((id: string) => {
    setSelectedItems(prev => {
      const newSet = new Set(prev);
      if (newSet.has(id)) {
        newSet.delete(id);
      } else {
        newSet.add(id);
      }
      return newSet;
    });
  }, []);

  // 전체 선택/해제
  const toggleSelectAll = useCallback(() => {
    if (selectedItems.size === paginatedData.length && paginatedData.length > 0) {
      setSelectedItems(new Set());
    } else {
      const allIds = new Set(paginatedData.map((item) => item.id));
      setSelectedItems(allIds);
    }
  }, [selectedItems.size, paginatedData]);

  // 핸들러
  const handleAddAttendance = useCallback(() => {
    setAttendanceDialogMode('create');
    setSelectedAttendance(null);
    setAttendanceDialogOpen(true);
  }, []);

  const handleAddReason = useCallback(() => {
    setReasonDialogOpen(true);
  }, []);

  const handleEditAttendance = useCallback((record: AttendanceRecord) => {
    setAttendanceDialogMode('edit');
    setSelectedAttendance(record);
    setAttendanceDialogOpen(true);
  }, []);

  const handleSaveAttendance = useCallback(async (data: AttendanceFormData) => {
    setIsSaving(true);
    try {
      if (attendanceDialogMode === 'create') {
        const result = await createAttendance(data);
        if (result.success && result.data) {
          invalidateDashboard('attendance');
          setAttendanceRecords(prev => [result.data!, ...prev]);
        } else {
          console.error('Create failed:', result.error);
        }
      } else if (selectedAttendance) {
        const result = await updateAttendance(selectedAttendance.id, data);
        if (result.success && result.data) {
          invalidateDashboard('attendance');
          setAttendanceRecords(prev =>
            prev.map(r => r.id === selectedAttendance.id ? result.data! : r)
          );
        } else {
          console.error('Update failed:', result.error);
        }
      }
      setAttendanceDialogOpen(false);
    } catch (error) {
      if (isNextRedirectError(error)) throw error;
      console.error('Save attendance error:', error);
    } finally {
      setIsSaving(false);
    }
  }, [attendanceDialogMode, selectedAttendance]);

  const handleSubmitReason = useCallback((data: ReasonFormData) => {
    // 문서 작성 화면으로 이동
    router.push(`/ko/hr/documents/new?mode=new&type=${data.reasonType}`);
  }, [router]);

  // ===== 엑셀 컬럼 정의 =====
  const excelColumns: ExcelColumn<AttendanceRecord>[] = useMemo(() => [
    { header: '부서', key: 'department' },
    { header: '직책', key: 'position' },
    { header: '이름', key: 'employeeName' },
    { header: '직급', key: 'rank' },
    { header: '기준일', key: 'baseDate' },
    { header: '출근', key: 'checkIn', transform: (value) => value ? String(value).substring(0, 5) : '-' },
    { header: '퇴근', key: 'checkOut', transform: (value) => value ? String(value).substring(0, 5) : '-' },
    { header: '휴게', key: 'breakTime', transform: (value) => value ? String(value) : '-' },
    { header: '연장근무', key: 'overtimeHours', transform: (value) => value ? String(value) : '-' },
    { header: '상태', key: 'status', transform: (value) => ATTENDANCE_STATUS_LABELS[value as AttendanceStatus] },
    { header: '사유', key: 'reason', transform: (value) => {
      const reason = value as AttendanceRecord['reason'];
      return reason?.label || '-';
    }},
  ], []);

  const handleReasonClick = useCallback((record: AttendanceRecord) => {
    if (record.reason?.documentId) {
      router.push(`/ko/hr/documents/${record.reason.documentId}?mode=view`);
    }
  }, [router]);

  // ===== filterConfig 기반 통합 필터 시스템 =====
  const filterConfig: FilterFieldConfig[] = useMemo(() => [
    {
      key: 'filter',
      label: '필터',
      type: 'single',
      options: FILTER_OPTIONS.filter(o => o.value !== 'all').map(o => ({
        value: o.value,
        label: o.label,
      })),
      allOptionLabel: '전체',
    },
    {
      key: 'sort',
      label: '정렬',
      type: 'single',
      options: SORT_OPTIONS.map(o => ({
        value: o.value,
        label: o.label,
      })),
    },
  ], []);

  const filterValues: FilterValues = useMemo(() => ({
    filter: filterOption,
    sort: sortOption,
  }), [filterOption, sortOption]);

  const handleFilterChange = useCallback((key: string, value: string | string[]) => {
    switch (key) {
      case 'filter':
        setFilterOption(value as FilterOption);
        break;
      case 'sort':
        setSortOption(value as SortOption);
        break;
    }
    setCurrentPage(1);
  }, []);

  const handleFilterReset = useCallback(() => {
    setFilterOption('all');
    setSortOption('dateDesc');
    setCurrentPage(1);
  }, []);

  // ===== UniversalListPage 설정 =====
  const attendanceConfig: UniversalListConfig<AttendanceRecord> = useMemo(() => ({
    title: '근태관리',
    description: '직원 출퇴근 및 근태 정보를 관리합니다',
    icon: Clock,
    basePath: '/hr/attendance-management',

    idField: 'id',

    actions: {
      getList: async () => ({
        success: true,
        data: mergedRecords,
        totalCount: mergedRecords.length,
      }),
    },

    columns: tableColumns,


    filterConfig: filterConfig,
    initialFilters: filterValues,
    filterTitle: '근태 필터',

    computeStats: () => statCards,

    // 검색창 (공통 컴포넌트에서 자동 생성)
    hideSearch: true,
    searchValue: searchValue,
    onSearchChange: setSearchValue,

    dateRangeSelector: {
      enabled: true,
      showPresets: true,
      startDate,
      endDate,
      onStartDateChange: setStartDate,
      onEndDateChange: setEndDate,
    },

    createButton: {
      label: '근태 등록',
      icon: Plus,
      onClick: handleAddAttendance,
    },

    // 헤더 액션 (근태 등록 버튼 옆에 표시)
    headerActions: () => (
      <Button variant="outline" onClick={handleAddReason}>
        <FileText className="w-4 h-4 mr-2" />
        사유 등록
      </Button>
    ),

    searchPlaceholder: '이름, 부서 검색...',

    // 엑셀 다운로드 설정 (프론트 mergedRecords 사용 - 미출근 직원 포함)
    excelDownload: {
      columns: excelColumns,
      filename: '근태현황',
      sheetName: '근태',
    },

    itemsPerPage: itemsPerPage,

    clientSideFiltering: true,

    searchFilter: (item, searchValue) => {
      const search = searchValue.toLowerCase();
      return (
        item.employeeName.toLowerCase().includes(search) ||
        item.department.toLowerCase().includes(search)
      );
    },

    customFilterFn: (items, filterValues) => {
      if (!items || items.length === 0) return items;
      let filtered = items;
      const filterOption = filterValues.filter as string;
      if (filterOption && filterOption !== 'all') {
        filtered = filtered.filter(r => r.status === filterOption);
      }
      return filtered;
    },

    customSortFn: (items, filterValues) => {
      const sortOption = filterValues.sort as SortOption || 'dateDesc';
      return [...items].sort((a, b) => {
        switch (sortOption) {
          case 'dateDesc':
            return new Date(b.baseDate).getTime() - new Date(a.baseDate).getTime();
          case 'dateAsc':
            return new Date(a.baseDate).getTime() - new Date(b.baseDate).getTime();
          case 'rank':
            return a.rank.localeCompare(b.rank, 'ko');
          case 'deptAsc':
            return a.department.localeCompare(b.department, 'ko');
          case 'deptDesc':
            return b.department.localeCompare(a.department, 'ko');
          case 'nameAsc':
            return a.employeeName.localeCompare(b.employeeName, 'ko');
          case 'nameDesc':
            return b.employeeName.localeCompare(a.employeeName, 'ko');
          default:
            return 0;
        }
      });
    },

    renderTableRow: (item, index, globalIndex, handlers) => {
      const { isSelected, onToggle } = handlers;

      return (
        <TableRow
          key={item.id}
          className="hover:bg-muted/50"
        >
          <TableCell className="text-center" onClick={(e) => e.stopPropagation()}>
            <Checkbox
              checked={isSelected}
              onCheckedChange={onToggle}
            />
          </TableCell>
          <TableCell className="text-center">{globalIndex}</TableCell>
          <TableCell>{item.department || '-'}</TableCell>
          <TableCell>{item.position || '-'}</TableCell>
          <TableCell>{item.employeeName}</TableCell>
          <TableCell>{item.rank || '-'}</TableCell>
          <TableCell>
            {item.baseDate ? format(new Date(item.baseDate), 'yyyy-MM-dd (E)', { locale: ko }) : '-'}
          </TableCell>
          <TableCell>{item.checkIn ? item.checkIn.substring(0, 5) : '-'}</TableCell>
          <TableCell>{item.checkOut ? item.checkOut.substring(0, 5) : '-'}</TableCell>
          <TableCell>{item.breakTime || '-'}</TableCell>
          <TableCell>{item.overtimeHours || '-'}</TableCell>
          <TableCell>
            {item.reason ? (
              <Button
                variant="link"
                size="sm"
                className="p-0 h-auto text-blue-600 hover:text-blue-800"
                onClick={() => handleReasonClick(item)}
              >
                {item.reason.label}
              </Button>
            ) : '-'}
          </TableCell>
        </TableRow>
      );
    },

    renderMobileCard: (item, index, globalIndex, handlers) => {
      const { isSelected, onToggle } = handlers;

      return (
        <ListMobileCard
          id={item.id}
          title={item.employeeName}
          headerBadges={
            <div className="flex items-center gap-2 flex-wrap">
              <Badge variant="outline" className="text-xs">
                {item.department || '-'}
              </Badge>
              <Badge variant="outline" className="text-xs">
                {item.rank || '-'}
              </Badge>
            </div>
          }
          statusBadge={
            <Badge className={ATTENDANCE_STATUS_COLORS[item.status]}>
              {ATTENDANCE_STATUS_LABELS[item.status]}
            </Badge>
          }
          isSelected={isSelected}
          onToggleSelection={onToggle}
          infoGrid={
            <div className="grid grid-cols-2 gap-x-4 gap-y-3">
              <InfoField label="직책" value={item.position || '-'} />
              <InfoField
                label="기준일"
                value={item.baseDate ? format(new Date(item.baseDate), 'yyyy-MM-dd') : '-'}
              />
              <InfoField label="출근" value={item.checkIn ? item.checkIn.substring(0, 5) : '-'} />
              <InfoField label="퇴근" value={item.checkOut ? item.checkOut.substring(0, 5) : '-'} />
              <InfoField label="휴게" value={item.breakTime || '-'} />
              <InfoField label="연장근무" value={item.overtimeHours || '-'} />
              {item.reason && (
                <InfoField label="사유" value={item.reason.label} />
              )}
            </div>
          }
        />
      );
    },

    renderDialogs: () => (
      <>
        {/* 근태 정보 다이얼로그 */}
        <AttendanceInfoDialog
          open={attendanceDialogOpen}
          onOpenChange={setAttendanceDialogOpen}
          mode={attendanceDialogMode}
          attendance={selectedAttendance}
          employees={employees}
          onSave={handleSaveAttendance}
        />

        {/* 사유 정보 다이얼로그 */}
        <ReasonInfoDialog
          open={reasonDialogOpen}
          onOpenChange={setReasonDialogOpen}
          employees={employees}
          onSubmit={handleSubmitReason}
        />
      </>
    ),
  }), [
    mergedRecords,
    tableColumns,
    filterConfig,
    filterValues,
    statCards,
    startDate,
    endDate,
    handleAddAttendance,
    excelColumns,
    handleAddReason,
    handleReasonClick,
    handleEditAttendance,
    attendanceDialogOpen,
    attendanceDialogMode,
    selectedAttendance,
    employees,
    handleSaveAttendance,
    reasonDialogOpen,
    handleSubmitReason,
  ]);

  return (
    <UniversalListPage<AttendanceRecord>
      config={attendanceConfig}
      initialData={mergedRecords}
      initialTotalCount={mergedRecords.length}
      externalIsLoading={isLoading}
    />
  );
}
