import { useState, useRef } from 'react';
import * as XLSX from 'xlsx';
import { Upload, FileSpreadsheet, AlertTriangle, CheckCircle2, XCircle, Loader2 } from 'lucide-react';
import { Button } from '@/components/ui/button';
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogHeader,
  DialogTitle,
} from '@/components/ui/dialog';
import { ScrollArea } from '@/components/ui/scroll-area';
import { Badge } from '@/components/ui/badge';
import { Checkbox } from '@/components/ui/checkbox';
import { supabase } from '@/integrations/supabase/client';
import { toast } from 'sonner';
import { useQueryClient } from '@tanstack/react-query';

interface ImportRow {
  reference: string;
  propertyReference: string;
  propertyAddress: string;
  tenantName: string;
  tenantEmail: string;
  tenantPhone: string;
  startDate: string;
  endDate: string;
  rent: number;
  rentPaymentFrequency: string;
  deposit: number;
  whereDepositHeld: string;
  lettingService: string;
  status: string;
  lettingFee: number;
  managementFee: number;
  isPeriodic: boolean;
  rentReviewDate: string;
  landlordName: string;
  landlordEmail: string;
  landlordPhone: string;
  landlordAddress: string;
  branch: string;
  isRentGuaranteed: boolean;
  tenancyAgreementSpecialClause: string;
  renewal: string;
  isHMO: boolean;
  breakClause: string;
  noticePeriod: string;
  leadStaff: string;
  inspectionFrequency: number;
}

interface ConflictItem {
  type: 'landlord' | 'tenant';
  name: string;
  email: string;
  existingId: string;
  rowIndex: number;
  overwrite: boolean;
}

interface TenancyImportDialogProps {
  open: boolean;
  onOpenChange: (open: boolean) => void;
}

export function TenancyImportDialog({ open, onOpenChange }: TenancyImportDialogProps) {
  const queryClient = useQueryClient();
  const fileInputRef = useRef<HTMLInputElement>(null);
  const [step, setStep] = useState<'upload' | 'preview' | 'conflicts' | 'importing' | 'complete'>('upload');
  const [parsedData, setParsedData] = useState<ImportRow[]>([]);
  const [conflicts, setConflicts] = useState<ConflictItem[]>([]);
  const [importResults, setImportResults] = useState({ success: 0, errors: 0, skipped: 0 });
  const [isProcessing, setIsProcessing] = useState(false);

  const parseExcelDate = (value: any): string | null => {
    if (!value) return null;
    if (typeof value === 'number') {
      const date = XLSX.SSF.parse_date_code(value);
      if (date) {
        return `${date.y}-${String(date.m).padStart(2, '0')}-${String(date.d).padStart(2, '0')}`;
      }
    }
    if (typeof value === 'string') {
      const parts = value.split('/');
      if (parts.length === 3) {
        const [month, day, year] = parts;
        return `20${year.length === 2 ? year : year.slice(-2)}-${month.padStart(2, '0')}-${day.padStart(2, '0')}`;
      }
    }
    return null;
  };

  const parseMoneyValue = (value: any): number => {
    if (!value) return 0;
    if (typeof value === 'number') return value;
    const cleaned = String(value).replace(/[£$,\s]/g, '').replace(/pcm|pa|pw/gi, '').trim();
    return parseFloat(cleaned) || 0;
  };

  const handleFileUpload = (event: React.ChangeEvent<HTMLInputElement>) => {
    const file = event.target.files?.[0];
    if (!file) return;

    setIsProcessing(true);
    const reader = new FileReader();
    reader.onload = (e) => {
      try {
        const data = new Uint8Array(e.target?.result as ArrayBuffer);
        const workbook = XLSX.read(data, { type: 'array' });
        const sheetName = workbook.SheetNames[0];
        const worksheet = workbook.Sheets[sheetName];
        const jsonData = XLSX.utils.sheet_to_json(worksheet, { header: 1 }) as any[][];

        if (jsonData.length < 2) {
          toast.error('No data found in the Excel file');
          setIsProcessing(false);
          return;
        }

        const headers = jsonData[0] as string[];
        const rows = jsonData.slice(1).filter(row => row.some(cell => cell != null && cell !== ''));

        const mapped: ImportRow[] = rows.map((row) => {
          const getValue = (headerName: string) => {
            const idx = headers.findIndex(h => h?.toLowerCase().replace(/[\s-]/g, '') === headerName.toLowerCase().replace(/[\s-]/g, ''));
            return idx >= 0 ? row[idx] : null;
          };

          return {
            reference: getValue('Reference') || '',
            propertyReference: getValue('PropertyReference') || getValue('Property Reference') || '',
            propertyAddress: getValue('Address') || '',
            tenantName: getValue('Tenant') || '',
            tenantEmail: getValue('TenantEmail') || getValue('Tenant Email') || '',
            tenantPhone: getValue('TenantPhoneNumber') || getValue('Tenant Phone Number') || '',
            startDate: parseExcelDate(getValue('StartDate') || getValue('Start Date')) || '',
            endDate: parseExcelDate(getValue('EndDate') || getValue('End Date')) || '',
            rent: parseMoneyValue(getValue('Rent')),
            rentPaymentFrequency: getValue('RentPaymentFrequency') || getValue('Rent Payment Frequency') || 'Monthly',
            deposit: parseMoneyValue(getValue('Deposit')),
            whereDepositHeld: getValue('WhereDepositHeld') || getValue('Where Deposit Held') || '',
            lettingService: getValue('LettingService') || getValue('Letting Service') || '',
            status: getValue('Status') || 'Active',
            lettingFee: parseMoneyValue(getValue('LettingFee') || getValue('Letting Fee')),
            managementFee: parseMoneyValue(getValue('ManagementFee') || getValue('Management Fee')),
            isPeriodic: String(getValue('IsPeriodic') || getValue('Is Periodic') || '').toLowerCase() === 'yes',
            rentReviewDate: parseExcelDate(getValue('RentReviewDate') || getValue('Rent Review Date')) || '',
            landlordName: getValue('Landlord') || '',
            landlordEmail: getValue('LandlordEmail') || getValue('Landlord Email') || '',
            landlordPhone: getValue('LandlordPhoneNumber') || getValue('Landlord Phone Number') || '',
            landlordAddress: getValue('LandlordAddress') || getValue('Landlord Address') || '',
            branch: getValue('Branch') || '',
            isRentGuaranteed: String(getValue('IsRentGuaranteed') || getValue('Is Rent Guaranteed') || '').toLowerCase() === 'yes',
            tenancyAgreementSpecialClause: getValue('TenancyAgreementSpecialClause') || getValue('Tenancy Agreement Special Clause') || '',
            renewal: getValue('Renewal') || '',
            isHMO: String(getValue('IsHMO') || getValue('Is HMO') || '').toLowerCase() === 'yes',
            breakClause: getValue('BreakClause') || getValue('Break Clause') || '',
            noticePeriod: getValue('NoticePeriod') || getValue('Notice Period') || '',
            leadStaff: getValue('LeadStaff') || getValue('Lead Staff') || '',
            inspectionFrequency: parseInt(getValue('Inspectionfrequency') || getValue('Inspection-frequency') || '0') || 0,
          };
        });

        setParsedData(mapped);
        setStep('preview');
      } catch (error) {
        console.error('Error parsing Excel file:', error);
        toast.error('Failed to parse Excel file');
      }
      setIsProcessing(false);
    };
    reader.readAsArrayBuffer(file);
  };

  const checkForConflicts = async () => {
    setIsProcessing(true);
    const foundConflicts: ConflictItem[] = [];

    const landlordEmails = [...new Set(parsedData.map(r => r.landlordEmail).filter(Boolean))];
    const tenantEmails = [...new Set(parsedData.map(r => r.tenantEmail).filter(Boolean))];

    // Check landlords
    if (landlordEmails.length > 0) {
      const { data: existingLandlords } = await supabase
        .from('contacts')
        .select('id, first_name, last_name, email')
        .in('email', landlordEmails);

      if (existingLandlords) {
        existingLandlords.forEach(landlord => {
          const rows = parsedData.filter(r => r.landlordEmail === landlord.email);
          rows.forEach((_, idx) => {
            foundConflicts.push({
              type: 'landlord',
              name: `${landlord.first_name} ${landlord.last_name}`,
              email: landlord.email,
              existingId: landlord.id,
              rowIndex: idx,
              overwrite: false,
            });
          });
        });
      }
    }

    // Check tenants
    if (tenantEmails.length > 0) {
      const { data: existingTenants } = await supabase
        .from('contacts')
        .select('id, first_name, last_name, email')
        .in('email', tenantEmails);

      if (existingTenants) {
        existingTenants.forEach(tenant => {
          const rows = parsedData.filter(r => r.tenantEmail === tenant.email);
          rows.forEach((_, idx) => {
            foundConflicts.push({
              type: 'tenant',
              name: `${tenant.first_name} ${tenant.last_name}`,
              email: tenant.email,
              existingId: tenant.id,
              rowIndex: idx,
              overwrite: false,
            });
          });
        });
      }
    }

    setConflicts(foundConflicts);
    setIsProcessing(false);

    if (foundConflicts.length > 0) {
      setStep('conflicts');
    } else {
      await performImport();
    }
  };

  const toggleConflictOverwrite = (index: number) => {
    setConflicts(prev => prev.map((c, i) => i === index ? { ...c, overwrite: !c.overwrite } : c));
  };

  const performImport = async () => {
    setStep('importing');
    setIsProcessing(true);

    let success = 0;
    let errors = 0;
    let skipped = 0;

    // Get or create Tenant and Landlord tags
    let tenantTagId: string | null = null;
    let landlordTagId: string | null = null;

    const { data: tenantTag } = await supabase.from('tags').select('id').ilike('name', 'tenant').single();
    if (tenantTag) {
      tenantTagId = tenantTag.id;
    } else {
      const { data: newTag } = await supabase.from('tags').insert({ name: 'Tenant', color: '#10b981' }).select().single();
      tenantTagId = newTag?.id || null;
    }

    const { data: landlordTag } = await supabase.from('tags').select('id').ilike('name', 'landlord').single();
    if (landlordTag) {
      landlordTagId = landlordTag.id;
    } else {
      const { data: newTag } = await supabase.from('tags').insert({ name: 'Landlord', color: '#f59e0b' }).select().single();
      landlordTagId = newTag?.id || null;
    }

    for (const row of parsedData) {
      try {
        // Handle landlord
        let landlordId: string | null = null;
        if (row.landlordEmail) {
          const existingConflict = conflicts.find(c => c.type === 'landlord' && c.email === row.landlordEmail);
          
          if (existingConflict && !existingConflict.overwrite) {
            landlordId = existingConflict.existingId;
          } else {
            const nameParts = row.landlordName.split(' ');
            const firstName = nameParts[0] || 'Unknown';
            const lastName = nameParts.slice(1).join(' ') || 'Landlord';

            if (existingConflict?.overwrite) {
              await supabase.from('contacts').update({
                first_name: firstName,
                last_name: lastName,
                phone: row.landlordPhone || null,
              }).eq('id', existingConflict.existingId);
              landlordId = existingConflict.existingId;
            } else {
              const { data: existingContact } = await supabase
                .from('contacts')
                .select('id')
                .eq('email', row.landlordEmail)
                .single();

              if (existingContact) {
                landlordId = existingContact.id;
              } else {
                const { data: newLandlord } = await supabase.from('contacts').insert({
                  first_name: firstName,
                  last_name: lastName,
                  email: row.landlordEmail,
                  phone: row.landlordPhone || null,
                  status: 'customer',
                }).select().single();

                if (newLandlord && landlordTagId) {
                  await supabase.from('contact_tags').insert({
                    contact_id: newLandlord.id,
                    tag_id: landlordTagId,
                  });
                }
                landlordId = newLandlord?.id || null;
              }
            }
          }
        }

        // Handle tenant
        let tenantId: string | null = null;
        if (row.tenantEmail) {
          const existingConflict = conflicts.find(c => c.type === 'tenant' && c.email === row.tenantEmail);
          
          if (existingConflict && !existingConflict.overwrite) {
            tenantId = existingConflict.existingId;
          } else {
            const nameParts = row.tenantName.replace(/^(Mr|Mrs|Ms|Miss|Dr)\s*/i, '').split(' ');
            const firstName = nameParts[0] || 'Unknown';
            const lastName = nameParts.slice(1).join(' ') || 'Tenant';

            if (existingConflict?.overwrite) {
              await supabase.from('contacts').update({
                first_name: firstName,
                last_name: lastName,
                phone: row.tenantPhone || null,
              }).eq('id', existingConflict.existingId);
              tenantId = existingConflict.existingId;
            } else {
              const { data: existingContact } = await supabase
                .from('contacts')
                .select('id')
                .eq('email', row.tenantEmail)
                .single();

              if (existingContact) {
                tenantId = existingContact.id;
              } else {
                const { data: newTenant } = await supabase.from('contacts').insert({
                  first_name: firstName,
                  last_name: lastName,
                  email: row.tenantEmail,
                  phone: row.tenantPhone || null,
                  status: 'customer',
                }).select().single();

                if (newTenant && tenantTagId) {
                  await supabase.from('contact_tags').insert({
                    contact_id: newTenant.id,
                    tag_id: tenantTagId,
                  });
                }
                tenantId = newTenant?.id || null;
              }
            }
          }
        }

        // Handle property
        let propertyId: string | null = null;
        if (row.propertyReference || row.propertyAddress) {
          const { data: existingProperty } = await supabase
            .from('properties')
            .select('id')
            .or(`reference.eq.${row.propertyReference},display_address.ilike.%${row.propertyAddress}%`)
            .single();

          if (existingProperty) {
            propertyId = existingProperty.id;
            if (landlordId) {
              await supabase.from('properties').update({ landlord_id: landlordId }).eq('id', propertyId);
            }
          } else {
            const addressParts = row.propertyAddress.split(',').map(p => p.trim());
            const { data: newProperty } = await supabase.from('properties').insert({
              reference: row.propertyReference || null,
              display_address: row.propertyAddress || null,
              address_line_1: addressParts[0] || null,
              town_city: addressParts[addressParts.length - 2] || null,
              postcode: addressParts[addressParts.length - 1] || null,
              landlord_id: landlordId,
              status: 'let',
            }).select().single();

            propertyId = newProperty?.id || null;
          }
        }

        // Create tenancy
        const { error: tenancyError } = await supabase.from('tenancies').insert({
          reference: row.reference || null,
          property_id: propertyId,
          tenant_id: tenantId,
          start_date: row.startDate || null,
          end_date: row.endDate || null,
          rent: row.rent || null,
          rent_payment_frequency: row.rentPaymentFrequency || null,
          deposit: row.deposit || null,
          where_deposit_held: row.whereDepositHeld || null,
          letting_service: row.lettingService || null,
          status: row.status?.toLowerCase() || 'active',
          letting_fee: row.lettingFee || null,
          management_fee: row.managementFee || null,
          is_periodic: row.isPeriodic,
          rent_review_date: row.rentReviewDate || null,
          branch: row.branch || null,
          is_rent_guaranteed: row.isRentGuaranteed,
          tenancy_agreement_special_clause: row.tenancyAgreementSpecialClause || null,
          renewal: row.renewal || null,
          is_hmo: row.isHMO,
          break_clause: row.breakClause || null,
          notice_period: row.noticePeriod || null,
          lead_staff: row.leadStaff || null,
          inspection_frequency: row.inspectionFrequency || null,
        });

        if (tenancyError) {
          console.error('Tenancy insert error:', tenancyError);
          errors++;
        } else {
          success++;
        }
      } catch (error) {
        console.error('Import row error:', error);
        errors++;
      }
    }

    setImportResults({ success, errors, skipped });
    setIsProcessing(false);
    setStep('complete');
    queryClient.invalidateQueries({ queryKey: ['tenancies'] });
    queryClient.invalidateQueries({ queryKey: ['contacts'] });
    queryClient.invalidateQueries({ queryKey: ['properties'] });
  };

  const handleClose = () => {
    setStep('upload');
    setParsedData([]);
    setConflicts([]);
    setImportResults({ success: 0, errors: 0, skipped: 0 });
    onOpenChange(false);
  };

  return (
    <Dialog open={open} onOpenChange={handleClose}>
      <DialogContent className="max-w-2xl">
        <DialogHeader>
          <DialogTitle className="flex items-center gap-2">
            <FileSpreadsheet className="h-5 w-5" />
            Import Tenancies
          </DialogTitle>
          <DialogDescription>
            {step === 'upload' && 'Upload an Excel file to import tenancies, tenants, and landlords'}
            {step === 'preview' && `Found ${parsedData.length} tenancies to import`}
            {step === 'conflicts' && 'Some contacts already exist. Choose how to handle them.'}
            {step === 'importing' && 'Importing data...'}
            {step === 'complete' && 'Import complete!'}
          </DialogDescription>
        </DialogHeader>

        <div className="py-4">
          {step === 'upload' && (
            <div
              className="border-2 border-dashed rounded-lg p-12 text-center cursor-pointer hover:border-primary transition-colors"
              onClick={() => fileInputRef.current?.click()}
            >
              <input
                ref={fileInputRef}
                type="file"
                accept=".xlsx,.xls"
                onChange={handleFileUpload}
                className="hidden"
              />
              {isProcessing ? (
                <Loader2 className="h-12 w-12 mx-auto text-muted-foreground animate-spin" />
              ) : (
                <Upload className="h-12 w-12 mx-auto text-muted-foreground" />
              )}
              <p className="mt-4 text-sm text-muted-foreground">
                Click to upload or drag and drop
              </p>
              <p className="text-xs text-muted-foreground mt-1">
                Excel files (.xlsx, .xls) supported
              </p>
            </div>
          )}

          {step === 'preview' && (
            <div className="space-y-4">
              <ScrollArea className="h-[300px] border rounded-lg">
                <table className="w-full text-sm">
                  <thead className="bg-muted sticky top-0">
                    <tr>
                      <th className="text-left p-2">Reference</th>
                      <th className="text-left p-2">Tenant</th>
                      <th className="text-left p-2">Property</th>
                      <th className="text-left p-2">Rent</th>
                    </tr>
                  </thead>
                  <tbody>
                    {parsedData.map((row, idx) => (
                      <tr key={idx} className="border-t">
                        <td className="p-2">{row.reference || '-'}</td>
                        <td className="p-2">{row.tenantName || row.tenantEmail || '-'}</td>
                        <td className="p-2 truncate max-w-[200px]">{row.propertyAddress || '-'}</td>
                        <td className="p-2">£{row.rent?.toLocaleString() || '0'}</td>
                      </tr>
                    ))}
                  </tbody>
                </table>
              </ScrollArea>
              <div className="flex justify-end gap-2">
                <Button variant="outline" onClick={handleClose}>Cancel</Button>
                <Button onClick={checkForConflicts} disabled={isProcessing}>
                  {isProcessing ? <Loader2 className="h-4 w-4 animate-spin mr-2" /> : null}
                  Continue
                </Button>
              </div>
            </div>
          )}

          {step === 'conflicts' && (
            <div className="space-y-4">
              <div className="bg-warning/10 border border-warning/30 rounded-lg p-4 flex items-start gap-3">
                <AlertTriangle className="h-5 w-5 text-warning shrink-0 mt-0.5" />
                <div>
                  <p className="font-medium">Existing contacts found</p>
                  <p className="text-sm text-muted-foreground">
                    Check the boxes next to contacts you want to update with new data.
                    Unchecked contacts will use existing data.
                  </p>
                </div>
              </div>
              <ScrollArea className="h-[250px]">
                <div className="space-y-2">
                  {conflicts.map((conflict, idx) => (
                    <div
                      key={idx}
                      className="flex items-center gap-3 p-3 border rounded-lg"
                    >
                      <Checkbox
                        checked={conflict.overwrite}
                        onCheckedChange={() => toggleConflictOverwrite(idx)}
                      />
                      <div className="flex-1">
                        <div className="flex items-center gap-2">
                          <span className="font-medium">{conflict.name}</span>
                          <Badge variant="secondary">{conflict.type}</Badge>
                        </div>
                        <p className="text-sm text-muted-foreground">{conflict.email}</p>
                      </div>
                      <span className="text-xs text-muted-foreground">
                        {conflict.overwrite ? 'Will update' : 'Will use existing'}
                      </span>
                    </div>
                  ))}
                </div>
              </ScrollArea>
              <div className="flex justify-end gap-2">
                <Button variant="outline" onClick={() => setStep('preview')}>Back</Button>
                <Button onClick={performImport}>
                  Import {parsedData.length} Tenancies
                </Button>
              </div>
            </div>
          )}

          {step === 'importing' && (
            <div className="text-center py-12">
              <Loader2 className="h-12 w-12 mx-auto animate-spin text-primary" />
              <p className="mt-4 text-muted-foreground">Importing tenancies...</p>
            </div>
          )}

          {step === 'complete' && (
            <div className="space-y-4">
              <div className="text-center py-8">
                <CheckCircle2 className="h-12 w-12 mx-auto text-green-500" />
                <p className="mt-4 font-medium">Import Complete!</p>
              </div>
              <div className="grid grid-cols-3 gap-4">
                <div className="text-center p-4 bg-green-50 dark:bg-green-900/20 rounded-lg">
                  <p className="text-2xl font-bold text-green-600">{importResults.success}</p>
                  <p className="text-sm text-muted-foreground">Imported</p>
                </div>
                <div className="text-center p-4 bg-red-50 dark:bg-red-900/20 rounded-lg">
                  <p className="text-2xl font-bold text-red-600">{importResults.errors}</p>
                  <p className="text-sm text-muted-foreground">Errors</p>
                </div>
                <div className="text-center p-4 bg-muted rounded-lg">
                  <p className="text-2xl font-bold">{importResults.skipped}</p>
                  <p className="text-sm text-muted-foreground">Skipped</p>
                </div>
              </div>
              <div className="flex justify-end">
                <Button onClick={handleClose}>Done</Button>
              </div>
            </div>
          )}
        </div>
      </DialogContent>
    </Dialog>
  );
}