import { describe, it, expect, vi, beforeEach } from 'vitest';

// Mock the database module
vi.mock('./db', () => ({
  getRequestById: vi.fn(),
  updateRequest: vi.fn(),
  createRequestHistory: vi.fn(),
  createAuditLog: vi.fn(),
}));

import * as db from './db';

describe('DSU (Direction des Services aux Usagers) - Cadre réservé', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  describe('Merging DSU data into formData', () => {
    it('should merge DSU data into existing formData for demande_salle', () => {
      const existingFormData = {
        nomAssociation: 'Association Test',
        sallesSelectionnees: ['Salle TOUCAN'],
        dateReservation: '2026-04-15',
        motifReservation: 'Réunion annuelle',
        formulaireType: 'reservation_salle_mjs',
      };

      const dsuData = {
        dateReception: '2026-03-10',
        avisDSU: 'favorable' as const,
        conditionsParticulieres: 'Nettoyage obligatoire',
        cautionRequise: true,
        montantCaution: '500',
        assuranceRequise: true,
        horairesImposes: '8h00 - 22h00',
        responsableDSU: 'Jean Dupont',
        dateDecision: '2026-03-11',
        observationsDSU: 'RAS',
      };

      // Simulate the merge logic from routers.ts
      const merged = { ...existingFormData };
      (merged as any).cadreDSU = {
        ...dsuData,
        rempliPar: 1,
        dateRemplissage: new Date().toISOString(),
      };

      const result = JSON.parse(JSON.stringify(merged));

      // Verify original data is preserved
      expect(result.nomAssociation).toBe('Association Test');
      expect(result.sallesSelectionnees).toEqual(['Salle TOUCAN']);
      expect(result.dateReservation).toBe('2026-04-15');
      expect(result.motifReservation).toBe('Réunion annuelle');

      // Verify DSU data is added
      expect(result.cadreDSU).toBeDefined();
      expect(result.cadreDSU.avisDSU).toBe('favorable');
      expect(result.cadreDSU.dateReception).toBe('2026-03-10');
      expect(result.cadreDSU.conditionsParticulieres).toBe('Nettoyage obligatoire');
      expect(result.cadreDSU.cautionRequise).toBe(true);
      expect(result.cadreDSU.montantCaution).toBe('500');
      expect(result.cadreDSU.assuranceRequise).toBe(true);
      expect(result.cadreDSU.horairesImposes).toBe('8h00 - 22h00');
      expect(result.cadreDSU.responsableDSU).toBe('Jean Dupont');
      expect(result.cadreDSU.dateDecision).toBe('2026-03-11');
      expect(result.cadreDSU.observationsDSU).toBe('RAS');
      expect(result.cadreDSU.rempliPar).toBe(1);
      expect(result.cadreDSU.dateRemplissage).toBeDefined();
    });

    it('should not add DSU data for non-salle request types', () => {
      const requestType = 'subvention_fonctionnement';
      const dsuData = {
        avisDSU: 'favorable' as const,
        responsableDSU: 'Jean Dupont',
      };

      // Simulate the condition check from routers.ts
      const shouldAddDsu = requestType === 'demande_salle';
      expect(shouldAddDsu).toBe(false);
    });

    it('should handle empty existing formData gracefully', () => {
      const existingFormData = null;
      const dsuData = {
        avisDSU: 'defavorable' as const,
        responsableDSU: 'Marie Martin',
        observationsDSU: 'Salle non disponible',
      };

      // Simulate the merge logic
      const parsed = existingFormData ? JSON.parse(existingFormData) : {};
      parsed.cadreDSU = {
        ...dsuData,
        rempliPar: 2,
        dateRemplissage: new Date().toISOString(),
      };

      const result = JSON.parse(JSON.stringify(parsed));
      expect(result.cadreDSU).toBeDefined();
      expect(result.cadreDSU.avisDSU).toBe('defavorable');
      expect(result.cadreDSU.responsableDSU).toBe('Marie Martin');
    });

    it('should handle favorable_avec_reserves avis correctly', () => {
      const existingFormData = { nomAssociation: 'Test' };
      const dsuData = {
        avisDSU: 'favorable_avec_reserves' as const,
        conditionsParticulieres: 'Sous réserve de présentation de l\'attestation d\'assurance',
        cautionRequise: true,
        montantCaution: '1000',
      };

      const merged = { ...existingFormData, cadreDSU: { ...dsuData, rempliPar: 1, dateRemplissage: new Date().toISOString() } };
      const result = JSON.parse(JSON.stringify(merged));

      expect(result.cadreDSU.avisDSU).toBe('favorable_avec_reserves');
      expect(result.cadreDSU.conditionsParticulieres).toContain('attestation d\'assurance');
      expect(result.cadreDSU.cautionRequise).toBe(true);
      expect(result.cadreDSU.montantCaution).toBe('1000');
    });

    it('should merge financial decision into an existing salle request dossier', () => {
      const existingFormData = {
        nomAssociation: 'Association Test',
        sallesSelectionnees: ['Salle TOUCAN'],
        dateReservation: '2026-06-20',
        cadreDSU: {
          responsableDSU: 'Agent DSU',
        },
      };

      const financialDecision = {
        financialMode: 'location_payante' as const,
        depositRequired: true,
        depositAmountCents: 45000,
        rentalAmountCents: 12500,
        pricingNotes: 'Facturation exceptionnelle pour occupation prolongée',
        contractStatus: 'a_generer' as const,
      };

      const merged = structuredClone(existingFormData) as any;
      merged.cadreDSU = {
        ...merged.cadreDSU,
        cautionRequise: financialDecision.depositRequired,
        montantCaution: String(financialDecision.depositAmountCents / 100),
        materielEvent: {
          financialDecision,
        },
      };

      expect(merged.cadreDSU.cautionRequise).toBe(true);
      expect(merged.cadreDSU.montantCaution).toBe('450');
      expect(merged.cadreDSU.materielEvent.financialDecision.financialMode).toBe('location_payante');
      expect(merged.cadreDSU.materielEvent.financialDecision.rentalAmountCents).toBe(12500);
    });

    it('should merge material financial decision into the existing material request data', () => {
      const existingFormData = {
        commune: 'Kourou',
        service: 'Vie associative',
        quantitesDemandees: { tente3x3: '2' },
        cadreDSU: {
          dateReception: '2026-05-10',
          materielEvent: {
            itemsAccordes: { tente3x3: true },
            quantitesAccordees: { tente3x3: '2' },
          },
        },
      };

      const financialDecision = {
        financialMode: 'location_payante' as const,
        depositRequired: true,
        depositAmountCents: 25000,
        rentalAmountCents: 9500,
        pricingNotes: 'Tarif exceptionnel pour événement intercommunal',
        contractStatus: 'a_generer' as const,
      };

      const merged = structuredClone(existingFormData) as any;
      merged.cadreDSU = {
        ...merged.cadreDSU,
        responsableDSU: 'Admin Logistique',
        materielEvent: {
          ...merged.cadreDSU.materielEvent,
          financialDecision,
        },
      };

      expect(merged.cadreDSU.materielEvent.itemsAccordes.tente3x3).toBe(true);
      expect(merged.cadreDSU.materielEvent.quantitesAccordees.tente3x3).toBe('2');
      expect(merged.cadreDSU.materielEvent.financialDecision.financialMode).toBe('location_payante');
      expect(merged.cadreDSU.materielEvent.financialDecision.depositRequired).toBe(true);
      expect(merged.cadreDSU.materielEvent.financialDecision.depositAmountCents).toBe(25000);
      expect(merged.cadreDSU.materielEvent.financialDecision.rentalAmountCents).toBe(9500);
      expect(merged.cadreDSU.materielEvent.financialDecision.pricingNotes).toContain('Tarif exceptionnel');
    });
  });

  describe('DSU avis labels mapping', () => {
    const avisDSULabels: Record<string, { label: string; className: string }> = {
      favorable: { label: 'Favorable', className: 'bg-green-100 text-green-800 border-green-200' },
      defavorable: { label: 'Défavorable', className: 'bg-red-100 text-red-800 border-red-200' },
      favorable_avec_reserves: { label: 'Favorable avec réserves', className: 'bg-amber-100 text-amber-800 border-amber-200' },
    };

    it('should have correct labels for all avis types', () => {
      expect(avisDSULabels.favorable.label).toBe('Favorable');
      expect(avisDSULabels.defavorable.label).toBe('Défavorable');
      expect(avisDSULabels.favorable_avec_reserves.label).toBe('Favorable avec réserves');
    });

    it('should have appropriate CSS classes for visual distinction', () => {
      expect(avisDSULabels.favorable.className).toContain('green');
      expect(avisDSULabels.defavorable.className).toContain('red');
      expect(avisDSULabels.favorable_avec_reserves.className).toContain('amber');
    });
  });

  describe('Process mutation with DSU data', () => {
    it('should call updateRequest with merged formData when DSU data is provided', async () => {
      const mockRequest = {
        id: 1,
        type: 'demande_salle',
        status: 'soumise',
        formData: JSON.stringify({
          nomAssociation: 'Test Asso',
          sallesSelectionnees: ['Salle TOUCAN'],
        }),
      };

      (db.getRequestById as any).mockResolvedValue(mockRequest);
      (db.updateRequest as any).mockResolvedValue(undefined);
      (db.createRequestHistory as any).mockResolvedValue(undefined);
      (db.createAuditLog as any).mockResolvedValue(undefined);

      const dsuData = {
        avisDSU: 'favorable' as const,
        responsableDSU: 'Admin Test',
        dateReception: '2026-03-10',
        dateDecision: '2026-03-11',
      };

      // Simulate the process logic
      const existingFormData = JSON.parse(mockRequest.formData);
      existingFormData.cadreDSU = {
        ...dsuData,
        rempliPar: 1,
        dateRemplissage: new Date().toISOString(),
      };
      const updatedFormData = JSON.stringify(existingFormData);

      await db.updateRequest(mockRequest.id, {
        status: 'validee' as any,
        commentaireAdmin: 'Approuvé',
        traitePar: 1,
        dateTraitement: new Date(),
        formData: updatedFormData,
      });

      expect(db.updateRequest).toHaveBeenCalledWith(
        1,
        expect.objectContaining({
          status: 'validee',
          formData: expect.stringContaining('cadreDSU'),
        })
      );

      // Verify the formData contains the DSU data
      const callArgs = (db.updateRequest as any).mock.calls[0][1];
      const parsedFormData = JSON.parse(callArgs.formData);
      expect(parsedFormData.cadreDSU.avisDSU).toBe('favorable');
      expect(parsedFormData.cadreDSU.responsableDSU).toBe('Admin Test');
      expect(parsedFormData.nomAssociation).toBe('Test Asso');
    });
  });
});
