import {
  BadRequestException,
  Injectable,
  NotFoundException,
} from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { CreateAgencyDto } from './dto/create-agency.dto';
import { UpdateAgencyDto } from './dto/update-agency.dto';
import { Agency } from './entities/agency.entity';

@Injectable()
export class AgenciesService {
  constructor(
    @InjectRepository(Agency)
    private readonly agencyRepository: Repository<Agency>,
  ) {}

  private normalizeName(name: string) {
    return name.trim();
  }

  private defaultPaymentSettings() {
    return {
      allowCash: true,
      allowCheque: true,
      allowCard: true,
      allowTpe: true,
      allowKonnect: false,
      allowFlouci: false,
      allowGooglePay: false,
      allowApplePay: false,
      allowBankTransfer: true,
      defaultPaymentMethod: 'cash',
    };
  }

  private defaultNotificationSettings() {
    return {
      emailNotifications: true,
      whatsappNotifications: false,
      dashboardAlerts: true,
      maintenanceReminderDays: 7,
      insuranceReminderDays: 15,
      vignetteReminderDays: 15,
      paymentReminderDays: 2,
    };
  }

  private defaultDocumentSettings() {
    return {
      showLogo: true,
      showTaxInfo: true,
      showQrCode: true,
      defaultPrintType: 'a4_blank',
      defaultFooter:
        'Document généré par DriveX - Compatible PDF / OCR / IA / Archivage numérique',
      contractTerms:
        'Le client reconnaît avoir reçu le véhicule en bon état et s’engage à le restituer dans les mêmes conditions.',
      invoiceTerms: 'Facture payable selon les conditions convenues.',
      receiptTerms: 'Reçu généré automatiquement.',
      signatureRequired: true,
      qrEnabled: true,
      ocrEnabled: true,
      aiReviewEnabled: false,
    };
  }

  async create(data: CreateAgencyDto) {
    const name = this.normalizeName(data.name);

    const existing = await this.agencyRepository.findOne({
      where: { name },
    });

    if (existing) {
      throw new BadRequestException('Agency name already exists');
    }

    const agency = this.agencyRepository.create({
      name,
      legalName: data.legalName,
      country: data.country,
      city: data.city,
      address: data.address,
      postalCode: data.postalCode,
      latitude: data.latitude,
      longitude: data.longitude,
      phone: data.phone,
      secondaryPhone: data.secondaryPhone,
      whatsapp: data.whatsapp,
      email: data.email,
      supportEmail: data.supportEmail,
      website: data.website,
      logoUrl: data.logoUrl,
      taxNumber: data.taxNumber,
      vatNumber: data.vatNumber,
      commercialRegister: data.commercialRegister,
      licenseNumber: data.licenseNumber,
      bankName: data.bankName,
      bankAccount: data.bankAccount,
      iban: data.iban,
      swift: data.swift,
      themeColor: data.themeColor || '#111827',
      secondaryColor: data.secondaryColor || '#ffffff',
      isActive: data.isActive ?? true,
      defaultCurrency: data.defaultCurrency || 'TND',
      defaultLanguage: data.defaultLanguage || 'fr',
      timezone: data.timezone || 'Africa/Tunis',
      workingHours: data.workingHours,
      pickupLocations: data.pickupLocations,
      returnLocations: data.returnLocations,
      parks: data.parks,
      paymentSettings: {
        ...this.defaultPaymentSettings(),
        ...(data.paymentSettings || {}),
      },
      notificationSettings: {
        ...this.defaultNotificationSettings(),
        ...(data.notificationSettings || {}),
      },
      documentSettings: {
        ...this.defaultDocumentSettings(),
        ...(data.documentSettings || {}),
      },
      notes: data.notes,
    });

    return this.agencyRepository.save(agency);
  }

  findAll() {
    return this.agencyRepository.find({
      order: { createdAt: 'DESC' },
    });
  }

  findActive() {
    return this.agencyRepository.find({
      where: { isActive: true },
      order: { name: 'ASC' },
    });
  }

  async findOne(id: number) {
    const agency = await this.agencyRepository.findOne({
      where: { id },
    });

    if (!agency) {
      throw new NotFoundException('Agency not found');
    }

    return agency;
  }

  async update(id: number, data: UpdateAgencyDto) {
    const agency = await this.findOne(id);

    if (data.name) {
      const name = this.normalizeName(data.name);

      const existing = await this.agencyRepository.findOne({
        where: { name },
      });

      if (existing && existing.id !== id) {
        throw new BadRequestException('Agency name already exists');
      }

      agency.name = name;
    }

    Object.assign(agency, {
      legalName: data.legalName ?? agency.legalName,
      country: data.country ?? agency.country,
      city: data.city ?? agency.city,
      address: data.address ?? agency.address,
      postalCode: data.postalCode ?? agency.postalCode,
      latitude: data.latitude ?? agency.latitude,
      longitude: data.longitude ?? agency.longitude,
      phone: data.phone ?? agency.phone,
      secondaryPhone: data.secondaryPhone ?? agency.secondaryPhone,
      whatsapp: data.whatsapp ?? agency.whatsapp,
      email: data.email ?? agency.email,
      supportEmail: data.supportEmail ?? agency.supportEmail,
      website: data.website ?? agency.website,
      logoUrl: data.logoUrl ?? agency.logoUrl,
      taxNumber: data.taxNumber ?? agency.taxNumber,
      vatNumber: data.vatNumber ?? agency.vatNumber,
      commercialRegister:
        data.commercialRegister ?? agency.commercialRegister,
      licenseNumber: data.licenseNumber ?? agency.licenseNumber,
      bankName: data.bankName ?? agency.bankName,
      bankAccount: data.bankAccount ?? agency.bankAccount,
      iban: data.iban ?? agency.iban,
      swift: data.swift ?? agency.swift,
      themeColor: data.themeColor ?? agency.themeColor,
      secondaryColor: data.secondaryColor ?? agency.secondaryColor,
      isActive: data.isActive ?? agency.isActive,
      defaultCurrency: data.defaultCurrency ?? agency.defaultCurrency,
      defaultLanguage: data.defaultLanguage ?? agency.defaultLanguage,
      timezone: data.timezone ?? agency.timezone,
      workingHours: data.workingHours ?? agency.workingHours,
      pickupLocations: data.pickupLocations ?? agency.pickupLocations,
      returnLocations: data.returnLocations ?? agency.returnLocations,
      parks: data.parks ?? agency.parks,
      paymentSettings: {
        ...this.defaultPaymentSettings(),
        ...(agency.paymentSettings || {}),
        ...(data.paymentSettings || {}),
      },
      notificationSettings: {
        ...this.defaultNotificationSettings(),
        ...(agency.notificationSettings || {}),
        ...(data.notificationSettings || {}),
      },
      documentSettings: {
        ...this.defaultDocumentSettings(),
        ...(agency.documentSettings || {}),
        ...(data.documentSettings || {}),
      },
      notes: data.notes ?? agency.notes,
    });

    return this.agencyRepository.save(agency);
  }

  async updateLogo(id: number, logoUrl: string) {
    const agency = await this.findOne(id);
    agency.logoUrl = logoUrl;
    return this.agencyRepository.save(agency);
  }

  async updateDocumentSettings(
    id: number,
    documentSettings: UpdateAgencyDto['documentSettings'],
  ) {
    const agency = await this.findOne(id);

    agency.documentSettings = {
      ...this.defaultDocumentSettings(),
      ...(agency.documentSettings || {}),
      ...(documentSettings || {}),
    };

    return this.agencyRepository.save(agency);
  }

  async updatePaymentSettings(
    id: number,
    paymentSettings: UpdateAgencyDto['paymentSettings'],
  ) {
    const agency = await this.findOne(id);

    agency.paymentSettings = {
      ...this.defaultPaymentSettings(),
      ...(agency.paymentSettings || {}),
      ...(paymentSettings || {}),
    };

    return this.agencyRepository.save(agency);
  }

  async updateNotificationSettings(
    id: number,
    notificationSettings: UpdateAgencyDto['notificationSettings'],
  ) {
    const agency = await this.findOne(id);

    agency.notificationSettings = {
      ...this.defaultNotificationSettings(),
      ...(agency.notificationSettings || {}),
      ...(notificationSettings || {}),
    };

    return this.agencyRepository.save(agency);
  }

  async remove(id: number) {
    const agency = await this.findOne(id);
    return this.agencyRepository.softRemove(agency);
  }
}