import React, { useState, useEffect } from 'react';
import { Button } from '@/components/ui/button';
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from '@/components/ui/table';
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
import { AlertCircle, Check, Loader2, Save, X } from 'lucide-react';
import { attendanceApi } from '@/services/attendanceApi';
import { toast } from 'sonner';
import * as XLSX from 'xlsx';
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert';
import { AttendanceRecord } from '@/types';

interface ParsedAttendance {
  employeeId: string;
  employeeName: string;
  date: string;
  inTime: string | null;
  outTime: string | null;
}

interface PunchRecord {
  employeeId: string;
  firstName: string;
  date: string;
  punchTime: string;
  punchState: string;
  deviceName: string;
  isInRecord: boolean;
}

interface ProcessedAttendance {
  employeeId: string;
  firstName: string;
  date: string;
  firstIn: string | null;
  lastOut: string | null;
  totalHours: string;
}

interface AttendanceParserProps {
  file: File;
  onComplete: () => void;
  onCancel: () => void;
}

const AttendanceParser: React.FC<AttendanceParserProps> = ({ file, onComplete, onCancel }) => {
  const [parsedData, setParsedData] = useState<AttendanceRecord[]>([]);
  const [processedData, setProcessedData] = useState<ProcessedAttendance[]>([]);
  const [errors, setErrors] = useState<string[]>([]);
  const [saving, setSaving] = useState(false);
  const [parsing, setParsing] = useState(true);
  const [showAllRecords, setShowAllRecords] = useState(false);

  useEffect(() => {
    parseExcelFile();
  }, [file]);

  const parseExcelFile = async () => {
    setParsing(true);
    try {
      const reader = new FileReader();
      reader.onload = (e) => {
        try {
          const data = new Uint8Array(e.target?.result as ArrayBuffer);
          const workbook = XLSX.read(data, { type: 'array' });
          
          // Get the first sheet
          const firstSheetName = workbook.SheetNames[0];
          const worksheet = workbook.Sheets[firstSheetName];
          
          // Convert to JSON
          const jsonData = XLSX.utils.sheet_to_json(worksheet);
          
          const validationErrors: string[] = [];
          const punchRecords: PunchRecord[] = [];
          
          // First, parse all punch records
          jsonData.forEach((row: any, index) => {
            try {
              if (!row['Employee ID'] || !row['Date'] || !row['Punch Time']) {
                validationErrors.push(`Row ${index + 2}: Missing required fields (Employee ID, Date, or Punch Time)`);
                return;
              }
              
              // Handle Employee ID as string or number
              const employeeId = String(row['Employee ID']).trim();
              if (!employeeId) {
                validationErrors.push(`Row ${index + 2}: Empty Employee ID`);
                return;
              }
              
              // Parse date
              let date: string;
              try {
                if (typeof row['Date'] === 'string') {
                  // Try to parse string date
                  const dateParts = row['Date'].split(/[-\/]/);
                  if (dateParts.length === 3) {
                    // Assuming format is DD-MM-YYYY or MM-DD-YYYY or YYYY-MM-DD
                    const dateObj = new Date(row['Date']);
                    if (isNaN(dateObj.getTime())) {
                      throw new Error('Invalid date format');
                    }
                    date = dateObj.toISOString().split('T')[0];
                  } else {
                    throw new Error('Invalid date format');
                  }
                } else if (typeof row['Date'] === 'number') {
                  // Excel date (serial number)
                  const excelDateValue = row['Date'];
                  const dateObj = XLSX.SSF.parse_date_code(excelDateValue);
                  const jsDate = new Date(dateObj.y, dateObj.m - 1, dateObj.d);
                  date = jsDate.toISOString().split('T')[0];
                } else {
                  throw new Error('Invalid date format');
                }
              } catch (error) {
                validationErrors.push(`Row ${index + 2}: Invalid date format`);
                return;
              }
              
              // Determine if this is an IN or OUT record based on Device Name or Punch State
              const deviceName = row['Device Name'] || '';
              const punchState = row['Punch State'] || '';
              
              let isInRecord = false;
              if (deviceName.includes('Syns-IN') || deviceName.includes('Syn-IN')) {
                isInRecord = true;
              } else if (deviceName.includes('Syns-OUT') || deviceName.includes('Syn-OUT')) {
                isInRecord = false;
              } else if (punchState === 'Check Out') {
                isInRecord = false;
              } else {
                // If no clear indicator, assume it's an IN record
                isInRecord = true;
              }
              
              // Create punch record
              const record: PunchRecord = {
                employeeId,
                firstName: row['First Name'] || '',
                date,
                punchTime: row['Punch Time'] || '',
                punchState,
                deviceName,
                isInRecord
              };
              
              punchRecords.push(record);
            } catch (error) {
              validationErrors.push(`Row ${index + 2}: ${(error as Error).message}`);
            }
          });
          
          // Process punch records to get first IN and last OUT for each employee by date
          const processedRecords = processAttendanceRecords(punchRecords);
          setProcessedData(processedRecords);
          
          // Convert to AttendanceRecord format for API
          const attendanceRecords: AttendanceRecord[] = processedRecords.map(record => ({
            id: 0, // ID will be assigned by the server
            employeeId: parseInt(record.employeeId) || 0, // Convert back to number for API
            date: record.date,
            inTime: record.firstIn,
            outTime: record.lastOut,
            status: 'Present', // Default to 'Present' if we have punch records
            comments: `Total Hours: ${record.totalHours}`
          }));
          
          setParsedData(attendanceRecords);
          setErrors(validationErrors);
        } catch (error) {
          console.error('Error parsing Excel file:', error);
          setErrors(['Could not parse Excel file. Please check the file format.']);
        } finally {
          setParsing(false);
        }
      };
      
      reader.onerror = () => {
        setErrors(['Error reading file']);
        setParsing(false);
      };
      
      reader.readAsArrayBuffer(file);
    } catch (error) {
      console.error('Error processing file:', error);
      setErrors(['Error processing file']);
      setParsing(false);
    }
  };

  // Calculate hours between two time strings
  const calculateHours = (inTime: string | null, outTime: string | null): string => {
    if (!inTime || !outTime) return '-';
    
    try {
      // Parse time strings (assuming format like "09:30:00")
      const [inHours, inMinutes, inSeconds] = inTime.split(':').map(Number);
      const [outHours, outMinutes, outSeconds] = outTime.split(':').map(Number);
      
      // Convert to minutes for easier calculation
      const inTotalMinutes = inHours * 60 + inMinutes + (inSeconds || 0) / 60;
      const outTotalMinutes = outHours * 60 + outMinutes + (outSeconds || 0) / 60;
      
      // Calculate difference
      let diffMinutes = outTotalMinutes - inTotalMinutes;
      
      // Handle case where employee left next day (after midnight)
      if (diffMinutes < 0) {
        diffMinutes += 24 * 60; // Add 24 hours
      }
      
      // Convert back to hours and minutes
      const hours = Math.floor(diffMinutes / 60);
      const minutes = Math.round(diffMinutes % 60);
      
      return `${hours}h ${minutes}m`;
    } catch (error) {
      console.error('Error calculating hours:', error);
      return '-';
    }
  };

  // Process attendance records to get first IN and last OUT for each employee by date
  const processAttendanceRecords = (punchRecords: PunchRecord[]): ProcessedAttendance[] => {
    // Group records by employeeId and date
    const groupedRecords: Record<string, PunchRecord[]> = {};
    
    punchRecords.forEach(record => {
      const key = `${record.employeeId}-${record.date}`;
      if (!groupedRecords[key]) {
        groupedRecords[key] = [];
      }
      groupedRecords[key].push(record);
    });
    
    // Process each group to find first IN and last OUT
    const result: ProcessedAttendance[] = [];
    
    Object.keys(groupedRecords).forEach(key => {
      const records = groupedRecords[key];
      
      // Sort records by punch time
      records.sort((a, b) => {
        return new Date(a.date + 'T' + a.punchTime).getTime() - 
               new Date(b.date + 'T' + b.punchTime).getTime();
      });
      
      // Find first IN
      const inRecords = records.filter(r => r.isInRecord);
      const firstInRecord = inRecords.length > 0 ? inRecords[0] : null;
      
      // Find last OUT
      const outRecords = records.filter(r => !r.isInRecord);
      const lastOutRecord = outRecords.length > 0 ? outRecords[outRecords.length - 1] : null;
      
      // Calculate total hours
      const totalHours = calculateHours(
        firstInRecord?.punchTime || null, 
        lastOutRecord?.punchTime || null
      );
      
      // Add to result
      result.push({
        employeeId: records[0].employeeId,
        firstName: records[0].firstName,
        date: records[0].date,
        firstIn: firstInRecord ? firstInRecord.punchTime : null,
        lastOut: lastOutRecord ? lastOutRecord.punchTime : null,
        totalHours
      });
    });
    
    // Sort by date and then by employee ID
    result.sort((a, b) => {
      const dateComparison = a.date.localeCompare(b.date);
      if (dateComparison !== 0) return dateComparison;
      
      // Try to sort by employee ID numerically if possible
      const empIdA = parseInt(a.employeeId);
      const empIdB = parseInt(b.employeeId);
      
      if (!isNaN(empIdA) && !isNaN(empIdB)) {
        return empIdA - empIdB;
      }
      
      // Fall back to string comparison
      return a.employeeId.localeCompare(b.employeeId);
    });
    
    return result;
  };

  const handleSave = async () => {
    if (parsedData.length === 0) {
      toast.error('No valid data to save');
      return;
    }
    
    setSaving(true);
    try {
      await attendanceApi.uploadBulk({
        month: 'Auto-detected',
        year: new Date().getFullYear(),
        records: parsedData
      });
      toast.success(`Successfully imported ${parsedData.length} attendance records`);
      onComplete();
    } catch (error) {
      console.error('Error saving attendance data:', error);
      toast.error('Failed to save attendance data');
    } finally {
      setSaving(false);
    }
  };

  // Export to Excel
  const handleExport = () => {
    try {
      // Create workbook and worksheet
      const wb = XLSX.utils.book_new();
      
      // Format data for export
      const exportData = processedData.map(record => ({
        'Date': record.date,
        'Employee ID': record.employeeId,
        'Name': record.firstName,
        'First IN': record.firstIn || '-',
        'Last OUT': record.lastOut || '-',
        'Total Hours': record.totalHours
      }));
      
      // Create worksheet from data
      const ws = XLSX.utils.json_to_sheet(exportData);
      
      // Add worksheet to workbook
      XLSX.utils.book_append_sheet(wb, ws, 'Attendance');
      
      // Generate Excel file and trigger download
      XLSX.writeFile(wb, 'Attendance_Summary.xlsx');
      
      toast.success('Excel file exported successfully');
    } catch (error) {
      console.error('Error exporting to Excel:', error);
      toast.error('Failed to export Excel file');
    }
  };

  // Get status badge
  const getStatusBadge = (status: string) => {
    const variants: Record<string, string> = {
      "Present": "bg-green-100 text-green-700 border-green-200",
      "Absent": "bg-red-100 text-red-700 border-red-200",
      "Half Day": "bg-yellow-100 text-yellow-700 border-yellow-200",
      "Leave": "bg-blue-100 text-blue-700 border-blue-200"
    };

    return (
      <Badge variant="outline" className={variants[status] || ""}>
        {status}
      </Badge>
    );
  };

  // Toggle between showing all records and only 100
  const toggleShowAllRecords = () => {
    setShowAllRecords(prev => !prev);
  };

  // Get records to display based on showAllRecords flag
  const getDisplayRecords = () => {
    return showAllRecords ? processedData : processedData.slice(0, 100);
  };

  return (
    <Card className="w-full">
      <CardHeader>
        <CardTitle className="flex items-center gap-2">
          {parsing && <Loader2 className="h-5 w-5 animate-spin text-primary" />}
          {!parsing && processedData.length > 0 && errors.length === 0 && <Check className="h-5 w-5 text-green-500" />}
          {!parsing && errors.length > 0 && <AlertCircle className="h-5 w-5 text-amber-500" />}
          Attendance File: {file.name}
        </CardTitle>
        <CardDescription>
          {parsing ? (
            'Parsing file, please wait...'
          ) : (
            <>
              {processedData.length} records found
              {errors.length > 0 && ` with ${errors.length} validation errors`}
            </>
          )}
        </CardDescription>
      </CardHeader>
      
      <CardContent className="space-y-4">
        {parsing ? (
          <div className="flex flex-col items-center justify-center py-12">
            <Loader2 className="h-12 w-12 animate-spin text-primary mb-4" />
            <p className="text-muted-foreground text-center">
              Processing file... This may take a moment.
            </p>
          </div>
        ) : (
          <>
            {/* Display validation errors */}
            {errors.length > 0 && (
              <Alert variant="destructive">
                <AlertCircle className="h-4 w-4" />
                <AlertTitle>Validation Errors</AlertTitle>
                <AlertDescription>
                  <div className="mt-2 max-h-40 overflow-y-auto text-sm">
                    <ul className="list-disc pl-5 space-y-1">
                      {errors.map((error, index) => (
                        <li key={index}>{error}</li>
                      ))}
                    </ul>
                  </div>
                </AlertDescription>
              </Alert>
            )}
            
            {/* Button controls */}
            {processedData.length > 0 && (
              <div className="flex justify-between items-center">
                <div className="flex gap-2">
                  {processedData.length > 100 && (
                    <Button 
                      variant="outline" 
                      onClick={toggleShowAllRecords}
                      size="sm"
                    >
                      {showAllRecords ? "Show First 100" : "Show All Records"}
                    </Button>
                  )}
                  <Button
                    variant="outline"
                    onClick={handleExport}
                    size="sm"
                  >
                    Export to Excel
                  </Button>
                </div>
                <div className="text-sm text-muted-foreground">
                  Showing {getDisplayRecords().length} of {processedData.length} records
                </div>
              </div>
            )}
            
            {/* Preview table */}
            {processedData.length > 0 && (
              <div className="border rounded-md overflow-auto max-h-96">
                <Table>
                  <TableHeader className="sticky top-0 bg-background">
                    <TableRow>
                      <TableHead>Date</TableHead>
                      <TableHead>Employee ID</TableHead>
                      <TableHead>Name</TableHead>
                      <TableHead>First IN</TableHead>
                      <TableHead>Last OUT</TableHead>
                      <TableHead>Total Hours</TableHead>
                    </TableRow>
                  </TableHeader>
                  <TableBody>
                    {getDisplayRecords().map((record, index) => (
                      <TableRow key={index}>
                        <TableCell>{record.date}</TableCell>
                        <TableCell>{record.employeeId}</TableCell>
                        <TableCell>{record.firstName}</TableCell>
                        <TableCell>{record.firstIn || '-'}</TableCell>
                        <TableCell>{record.lastOut || '-'}</TableCell>
                        <TableCell>{record.totalHours}</TableCell>
                      </TableRow>
                    ))}
                  </TableBody>
                </Table>
              </div>
            )}
            
            {processedData.length === 0 && !parsing && (
              <div className="text-center py-8">
                <AlertCircle className="h-12 w-12 text-amber-500 mx-auto mb-2" />
                <h3 className="text-lg font-medium">No valid data found</h3>
                <p className="text-muted-foreground mt-1">
                  The file doesn't contain any valid attendance records.
                  Please check the file format and try again.
                </p>
              </div>
            )}
          </>
        )}
      </CardContent>
      
      <CardFooter className="flex justify-end gap-2">
        <Button variant="outline" onClick={onCancel} disabled={saving}>
          Cancel
        </Button>
        <Button 
          onClick={handleSave} 
          disabled={parsedData.length === 0 || saving || parsing} 
          className="flex items-center gap-2"
        >
          {saving && <Loader2 className="h-4 w-4 animate-spin" />}
          {saving ? 'Saving...' : 'Import Data'}
        </Button>
      </CardFooter>
    </Card>
  );
};

export default AttendanceParser; 