import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { documentsApi } from '../api/documents.api';
import type { CreateDocumentRequest, UpdateDocumentRequest, DocumentRecord } from '../types/documents.types';

export function useDocumentsList(filters?: { vehicleId?: string; type?: string; expiresBefore?: string }) {
  const queryKey = ['documents', filters];
  const query = useQuery({
    queryKey,
    queryFn: () => documentsApi.list(filters),
    networkMode: 'offlineFirst',
  });
  return query;
}

export function useDocument(id?: string) {
  const query = useQuery({
    queryKey: ['document', id],
    queryFn: () => documentsApi.get(id!),
    enabled: !!id,
    networkMode: 'offlineFirst',
  });
  return query;
}

export function useCreateDocument() {
  const qc = useQueryClient();
  return useMutation({
    mutationFn: (payload: CreateDocumentRequest) => documentsApi.create(payload),
    onMutate: async (newDocument) => {
      // Cancel any outgoing refetches to avoid overwriting optimistic update
      await qc.cancelQueries({ queryKey: ['documents'] });

      // Snapshot previous value
      const previousDocuments = qc.getQueryData(['documents']);

      // Create optimistic document record
      const optimisticDocument: DocumentRecord = {
        id: `temp-${Date.now()}`, // Temporary ID
        userId: '', // Will be filled by server
        vehicleId: newDocument.vehicleId,
        documentType: newDocument.documentType,
        title: newDocument.title,
        notes: newDocument.notes || null,
        details: newDocument.details || null,
        storageBucket: null,
        storageKey: null,
        fileName: null,
        contentType: null,
        fileSize: null,
        fileHash: null,
        issuedDate: newDocument.issuedDate || null,
        expirationDate: newDocument.expirationDate || null,
        emailNotifications: newDocument.emailNotifications,
        scanForMaintenance: newDocument.scanForMaintenance,
        sharedVehicleIds: newDocument.sharedVehicleIds || [],
        createdAt: new Date().toISOString(),
        updatedAt: new Date().toISOString(),
        deletedAt: null,
      };

      // Optimistically update cache
      qc.setQueryData(['documents'], (old: DocumentRecord[] | undefined) => {
        return old ? [optimisticDocument, ...old] : [optimisticDocument];
      });

      // Return context object with rollback data
      return { previousDocuments };
    },
    onError: (_err, _newDocument, context) => {
      // Rollback to previous state on error
      if (context?.previousDocuments) {
        qc.setQueryData(['documents'], context.previousDocuments);
      }
    },
    onSettled: () => {
      // Always refetch to ensure consistency
      qc.invalidateQueries({ queryKey: ['documents'] });
    },
    networkMode: 'offlineFirst',
  });
}

export function useUpdateDocument(id: string) {
  const qc = useQueryClient();
  return useMutation({
    mutationFn: (payload: UpdateDocumentRequest) => documentsApi.update(id, payload),
    onMutate: async (updateData) => {
      // Cancel outgoing refetches
      await qc.cancelQueries({ queryKey: ['document', id] });
      await qc.cancelQueries({ queryKey: ['documents'] });

      // Snapshot previous values
      const previousDocument = qc.getQueryData(['document', id]);
      const previousDocuments = qc.getQueryData(['documents']);

      // Optimistically update individual document
      qc.setQueryData(['document', id], (old: DocumentRecord | undefined) => {
        if (!old) return old;
        return {
          ...old,
          ...updateData,
          updatedAt: new Date().toISOString(),
        };
      });

      // Optimistically update documents list
      qc.setQueryData(['documents'], (old: DocumentRecord[] | undefined) => {
        if (!old) return old;
        return old.map(doc =>
          doc.id === id
            ? { ...doc, ...updateData, updatedAt: new Date().toISOString() }
            : doc
        );
      });

      return { previousDocument, previousDocuments };
    },
    onError: (_err, _updateData, context) => {
      // Rollback on error
      if (context?.previousDocument) {
        qc.setQueryData(['document', id], context.previousDocument);
      }
      if (context?.previousDocuments) {
        qc.setQueryData(['documents'], context.previousDocuments);
      }
    },
    onSettled: () => {
      // Refetch to ensure consistency
      qc.invalidateQueries({ queryKey: ['document', id] });
      qc.invalidateQueries({ queryKey: ['documents'] });
    },
    networkMode: 'offlineFirst',
  });
}

export function useDeleteDocument() {
  const qc = useQueryClient();
  return useMutation({
    mutationFn: (id: string) => documentsApi.remove(id),
    onMutate: async (id) => {
      // Cancel outgoing refetches
      await qc.cancelQueries({ queryKey: ['documents'] });
      await qc.cancelQueries({ queryKey: ['document', id] });

      // Snapshot previous values
      const previousDocuments = qc.getQueryData(['documents']);
      const previousDocument = qc.getQueryData(['document', id]);

      // Optimistically remove from documents list
      qc.setQueryData(['documents'], (old: DocumentRecord[] | undefined) => {
        if (!old) return old;
        return old.filter(doc => doc.id !== id);
      });

      // Remove individual document from cache
      qc.removeQueries({ queryKey: ['document', id] });

      return { previousDocuments, previousDocument, deletedId: id };
    },
    onError: (_err, _id, context) => {
      // Rollback on error
      if (context?.previousDocuments) {
        qc.setQueryData(['documents'], context.previousDocuments);
      }
      if (context?.previousDocument && context.deletedId) {
        qc.setQueryData(['document', context.deletedId], context.previousDocument);
      }
    },
    onSettled: () => {
      // Refetch to ensure consistency
      qc.invalidateQueries({ queryKey: ['documents'] });
    },
    networkMode: 'offlineFirst',
  });
}

export function useUploadDocument(id: string) {
  const qc = useQueryClient();
  return useMutation({
    mutationFn: (file: File) => documentsApi.upload(id, file),
    onMutate: async (file) => {
      // Cancel outgoing refetches
      await qc.cancelQueries({ queryKey: ['document', id] });
      await qc.cancelQueries({ queryKey: ['documents'] });

      // Snapshot previous values
      const previousDocument = qc.getQueryData(['document', id]);
      const previousDocuments = qc.getQueryData(['documents']);

      // Optimistically update with upload in progress state
      const optimisticUpdate = {
        fileName: file.name,
        contentType: file.type,
        fileSize: file.size,
        updatedAt: new Date().toISOString(),
      };

      // Update individual document
      qc.setQueryData(['document', id], (old: DocumentRecord | undefined) => {
        if (!old) return old;
        return { ...old, ...optimisticUpdate };
      });

      // Update documents list
      qc.setQueryData(['documents'], (old: DocumentRecord[] | undefined) => {
        if (!old) return old;
        return old.map(doc =>
          doc.id === id ? { ...doc, ...optimisticUpdate } : doc
        );
      });

      return { previousDocument, previousDocuments };
    },
    onError: (_err, _file, context) => {
      // Rollback on error
      if (context?.previousDocument) {
        qc.setQueryData(['document', id], context.previousDocument);
      }
      if (context?.previousDocuments) {
        qc.setQueryData(['documents'], context.previousDocuments);
      }
    },
    onSettled: () => {
      // Refetch to get server state (including storage_bucket, storage_key, etc.)
      qc.invalidateQueries({ queryKey: ['document', id] });
      qc.invalidateQueries({ queryKey: ['documents'] });
    },
    networkMode: 'offlineFirst',
  });
}

export function useDocumentsByVehicle(vehicleId?: string) {
  const query = useQuery({
    queryKey: ['documents-by-vehicle', vehicleId],
    queryFn: () => documentsApi.listByVehicle(vehicleId!),
    enabled: !!vehicleId,
    networkMode: 'offlineFirst',
  });
  return query;
}

export function useAddSharedVehicle() {
  const qc = useQueryClient();
  return useMutation({
    mutationFn: ({ docId, vehicleId }: { docId: string; vehicleId: string }) =>
      documentsApi.addSharedVehicle(docId, vehicleId),
    onMutate: async ({ docId, vehicleId }) => {
      // Cancel outgoing refetches
      await qc.cancelQueries({ queryKey: ['document', docId] });
      await qc.cancelQueries({ queryKey: ['documents'] });
      await qc.cancelQueries({ queryKey: ['documents-by-vehicle'] });

      // Snapshot previous values
      const previousDocument = qc.getQueryData(['document', docId]);
      const previousDocuments = qc.getQueryData(['documents']);

      // Optimistically update individual document
      qc.setQueryData(['document', docId], (old: DocumentRecord | undefined) => {
        if (!old) return old;
        return {
          ...old,
          sharedVehicleIds: [...old.sharedVehicleIds, vehicleId],
          updatedAt: new Date().toISOString(),
        };
      });

      // Optimistically update documents list
      qc.setQueryData(['documents'], (old: DocumentRecord[] | undefined) => {
        if (!old) return old;
        return old.map(doc =>
          doc.id === docId
            ? { ...doc, sharedVehicleIds: [...doc.sharedVehicleIds, vehicleId], updatedAt: new Date().toISOString() }
            : doc
        );
      });

      return { previousDocument, previousDocuments };
    },
    onError: (_err, { docId }, context) => {
      // Rollback on error
      if (context?.previousDocument) {
        qc.setQueryData(['document', docId], context.previousDocument);
      }
      if (context?.previousDocuments) {
        qc.setQueryData(['documents'], context.previousDocuments);
      }
    },
    onSettled: () => {
      // Refetch to ensure consistency
      qc.invalidateQueries({ queryKey: ['documents'] });
      qc.invalidateQueries({ queryKey: ['documents-by-vehicle'] });
    },
    networkMode: 'offlineFirst',
  });
}

export function useRemoveVehicleFromDocument() {
  const qc = useQueryClient();
  return useMutation({
    mutationFn: ({ docId, vehicleId }: { docId: string; vehicleId: string }) =>
      documentsApi.removeVehicleFromDocument(docId, vehicleId),
    onMutate: async ({ docId, vehicleId }) => {
      // Cancel outgoing refetches
      await qc.cancelQueries({ queryKey: ['document', docId] });
      await qc.cancelQueries({ queryKey: ['documents'] });
      await qc.cancelQueries({ queryKey: ['documents-by-vehicle'] });

      // Snapshot previous values
      const previousDocument = qc.getQueryData(['document', docId]);
      const previousDocuments = qc.getQueryData(['documents']);

      // Optimistically update individual document
      qc.setQueryData(['document', docId], (old: DocumentRecord | undefined) => {
        if (!old) return old;
        return {
          ...old,
          sharedVehicleIds: old.sharedVehicleIds.filter(id => id !== vehicleId),
          updatedAt: new Date().toISOString(),
        };
      });

      // Optimistically update documents list
      qc.setQueryData(['documents'], (old: DocumentRecord[] | undefined) => {
        if (!old) return old;
        return old.map(doc =>
          doc.id === docId
            ? { ...doc, sharedVehicleIds: doc.sharedVehicleIds.filter(id => id !== vehicleId), updatedAt: new Date().toISOString() }
            : doc
        );
      });

      return { previousDocument, previousDocuments };
    },
    onError: (_err, { docId }, context) => {
      // Rollback on error
      if (context?.previousDocument) {
        qc.setQueryData(['document', docId], context.previousDocument);
      }
      if (context?.previousDocuments) {
        qc.setQueryData(['documents'], context.previousDocuments);
      }
    },
    onSettled: () => {
      // Refetch to ensure consistency
      qc.invalidateQueries({ queryKey: ['documents'] });
      qc.invalidateQueries({ queryKey: ['documents-by-vehicle'] });
    },
    networkMode: 'offlineFirst',
  });
}
