import {
  Injectable,
  ConflictException,
  NotFoundException,
} from '@nestjs/common';
import { TransportPricingRepository } from './repositories/transport-pricing.repository';
import { CreateTransportPricingDto, UpdateTransportPricingDto } from './dto';
import { serviceMessages } from '../../common/constants/messages';

const MSG = serviceMessages('Transport pricing');

@Injectable()
export class TransportPricingService {
  constructor(private readonly repo: TransportPricingRepository) {}

  async findByDestination(destinationId: string, currencyId?: string) {
    return this.repo.findByDestinationAndCurrency(destinationId, currencyId);
  }

  async findPaginated(query: { destinationId?: string; currencyId?: string; search?: string; page?: number; limit?: number }) {
    return this.repo.findPaginatedByRoutes(query);
  }

  async getCabTypes(destinationId: string) {
    return this.repo.getDistinctCabTypes(destinationId);
  }

  async findById(id: string) {
    const item = await this.repo.findById(id);
    if (!item) throw new NotFoundException(MSG.NOT_FOUND);
    return item;
  }

  async create(dto: CreateTransportPricingDto) {
    const existing = await this.repo.findExisting(dto.transport_service_id, dto.cab_type, dto.currency_id);
    if (existing) throw new ConflictException('Pricing for this service + cab type + currency already exists');

    // Check for soft-deleted record and reactivate instead of creating new
    const softDeleted = await this.repo.findSoftDeleted(dto.transport_service_id, dto.cab_type, dto.currency_id);
    if (softDeleted) {
      await this.repo.reactivate(softDeleted.id, {
        destination_id: dto.destination_id,
        category: dto.category,
        default_price: dto.default_price ?? null,
        season_1_price: dto.season_1_price ?? null,
        season_2_price: dto.season_2_price ?? null,
        season_3_price: dto.season_3_price ?? null,
        season_4_price: dto.season_4_price ?? null,
        season_5_price: dto.season_5_price ?? null,
      } as any);
      return { id: softDeleted.id, message: MSG.CREATED };
    }

    const item = await this.repo.save({
      destination_id: dto.destination_id,
      transport_service_id: dto.transport_service_id,
      category: dto.category,
      cab_type: dto.cab_type,
      currency_id: dto.currency_id,
      default_price: dto.default_price ?? null,
      season_1_price: dto.season_1_price ?? null,
      season_2_price: dto.season_2_price ?? null,
      season_3_price: dto.season_3_price ?? null,
      season_4_price: dto.season_4_price ?? null,
      season_5_price: dto.season_5_price ?? null,
    });

    return { id: item.id, message: MSG.CREATED };
  }

  async bulkSave(items: CreateTransportPricingDto[]) {
    const results: any[] = [];
    for (const dto of items) {
      const existing = await this.repo.findExisting(dto.transport_service_id, dto.cab_type, dto.currency_id);
      if (existing) {
        // Update existing
        const updateData: any = {};
        for (const field of ['default_price', 'season_1_price', 'season_2_price', 'season_3_price', 'season_4_price', 'season_5_price', 'category']) {
          if ((dto as any)[field] !== undefined) updateData[field] = (dto as any)[field];
        }
        await this.repo.update(existing.id, updateData);
        results.push({ id: existing.id, action: 'updated' });
      } else {
        // Check for soft-deleted record and reactivate
        const softDeleted = await this.repo.findSoftDeleted(dto.transport_service_id, dto.cab_type, dto.currency_id);
        if (softDeleted) {
          await this.repo.reactivate(softDeleted.id, {
            destination_id: dto.destination_id,
            category: dto.category,
            default_price: dto.default_price ?? null,
            season_1_price: dto.season_1_price ?? null,
            season_2_price: dto.season_2_price ?? null,
            season_3_price: dto.season_3_price ?? null,
            season_4_price: dto.season_4_price ?? null,
            season_5_price: dto.season_5_price ?? null,
          } as any);
          results.push({ id: softDeleted.id, action: 'reactivated' });
        } else {
          // Create new
          const item = await this.repo.save({
            destination_id: dto.destination_id,
            transport_service_id: dto.transport_service_id,
            category: dto.category,
            cab_type: dto.cab_type,
            currency_id: dto.currency_id,
            default_price: dto.default_price ?? null,
            season_1_price: dto.season_1_price ?? null,
            season_2_price: dto.season_2_price ?? null,
            season_3_price: dto.season_3_price ?? null,
            season_4_price: dto.season_4_price ?? null,
            season_5_price: dto.season_5_price ?? null,
          });
          results.push({ id: item.id, action: 'created' });
        }
      }
    }
    return { results, message: `${results.length} pricing entries saved` };
  }

  async update(id: string, dto: UpdateTransportPricingDto) {
    const item = await this.repo.findById(id);
    if (!item) throw new NotFoundException(MSG.NOT_FOUND);

    const updateData: any = {};
    for (const field of ['default_price', 'season_1_price', 'season_2_price', 'season_3_price', 'season_4_price', 'season_5_price', 'category', 'cab_type']) {
      if ((dto as any)[field] !== undefined) updateData[field] = (dto as any)[field];
    }

    await this.repo.update(id, updateData);
    return { id, message: MSG.UPDATED };
  }

  async remove(id: string) {
    const item = await this.repo.findById(id);
    if (!item) throw new NotFoundException(MSG.NOT_FOUND);

    // Hard delete — prevents ghost records causing unique constraint errors on re-add
    await (this.repo as any).repo.delete(id);
    return { message: MSG.DELETED };
  }
}
