import { Repository, FindOptionsWhere, ILike, Between, In } from 'typeorm';
import { AppDataSource } from '../../../config/typeorm.js';
import { CrucePeaje, TipoPagoPeaje } from '../entities/cruce-peaje.entity.js';
import { EstadoGasto } from '../entities/carga-combustible.entity.js';

/**
 * Search parameters for toll crossings
 */
export interface CrucePeajeSearchParams {
  tenantId: string;
  search?: string;
  unidadId?: string;
  viajeId?: string;
  operadorId?: string;
  tipoPago?: string;
  estado?: EstadoGasto;
  fechaDesde?: Date;
  fechaHasta?: Date;
  limit?: number;
  offset?: number;
}

/**
 * DTO for creating a toll crossing
 */
export interface CreateCrucePeajeDto {
  unidadId: string;
  viajeId?: string;
  operadorId?: string;
  casetaNombre: string;
  casetaCodigo?: string;
  carretera?: string;
  monto: number;
  tipoPago?: string;
  tagNumero?: string;
  latitud?: number;
  longitud?: number;
  fechaCruce: Date;
  numeroTicket?: string;
  fotoTicketUrl?: string;
}

/**
 * DTO for updating a toll crossing
 */
export interface UpdateCrucePeajeDto extends Partial<CreateCrucePeajeDto> {
  estado?: EstadoGasto;
}

/**
 * Service for managing toll crossings (Cruces de Peaje)
 */
export class CrucePeajeService {
  private repository: Repository<CrucePeaje>;

  constructor() {
    this.repository = AppDataSource.getRepository(CrucePeaje);
  }

  /**
   * Find all toll crossings with filters
   */
  async findAll(params: CrucePeajeSearchParams): Promise<{ data: CrucePeaje[]; total: number }> {
    const {
      tenantId,
      search,
      unidadId,
      viajeId,
      operadorId,
      tipoPago,
      estado,
      fechaDesde,
      fechaHasta,
      limit = 50,
      offset = 0,
    } = params;

    const where: FindOptionsWhere<CrucePeaje>[] = [];
    const baseWhere: FindOptionsWhere<CrucePeaje> = { tenantId };

    if (unidadId) {
      baseWhere.unidadId = unidadId;
    }

    if (viajeId) {
      baseWhere.viajeId = viajeId;
    }

    if (operadorId) {
      baseWhere.operadorId = operadorId;
    }

    if (tipoPago) {
      baseWhere.tipoPago = tipoPago;
    }

    if (estado) {
      baseWhere.estado = estado;
    }

    if (fechaDesde && fechaHasta) {
      baseWhere.fechaCruce = Between(fechaDesde, fechaHasta);
    }

    if (search) {
      where.push(
        { ...baseWhere, casetaNombre: ILike(`%${search}%`) },
        { ...baseWhere, casetaCodigo: ILike(`%${search}%`) },
        { ...baseWhere, carretera: ILike(`%${search}%`) }
      );
    } else {
      where.push(baseWhere);
    }

    const [data, total] = await this.repository.findAndCount({
      where,
      take: limit,
      skip: offset,
      order: { fechaCruce: 'DESC' },
    });

    return { data, total };
  }

  /**
   * Find a single toll crossing by ID
   */
  async findOne(tenantId: string, id: string): Promise<CrucePeaje | null> {
    return this.repository.findOne({
      where: { id, tenantId },
    });
  }

  /**
   * Create a new toll crossing
   */
  async create(tenantId: string, dto: CreateCrucePeajeDto): Promise<CrucePeaje> {
    const cruce = this.repository.create({
      ...dto,
      tenantId,
      estado: EstadoGasto.APROBADO, // Toll crossings are auto-approved by default
    });

    return this.repository.save(cruce);
  }

  /**
   * Update an existing toll crossing
   */
  async update(
    tenantId: string,
    id: string,
    dto: UpdateCrucePeajeDto
  ): Promise<CrucePeaje | null> {
    const cruce = await this.findOne(tenantId, id);
    if (!cruce) return null;

    Object.assign(cruce, dto);
    return this.repository.save(cruce);
  }

  /**
   * Delete a toll crossing
   */
  async delete(tenantId: string, id: string): Promise<boolean> {
    const cruce = await this.findOne(tenantId, id);
    if (!cruce) return false;

    const result = await this.repository.delete(id);
    return (result.affected ?? 0) > 0;
  }

  /**
   * Get toll crossings by unit
   */
  async getCrucesPorUnidad(unidadId: string, tenantId: string): Promise<CrucePeaje[]> {
    return this.repository.find({
      where: { unidadId, tenantId },
      order: { fechaCruce: 'DESC' },
      take: 50,
    });
  }

  /**
   * Get toll crossings by trip
   */
  async getCrucesPorViaje(viajeId: string, tenantId: string): Promise<CrucePeaje[]> {
    return this.repository.find({
      where: { viajeId, tenantId },
      order: { fechaCruce: 'ASC' },
    });
  }

  /**
   * Calculate total toll cost for a trip
   */
  async getTotalPeajesViaje(viajeId: string, tenantId: string): Promise<number> {
    const cruces = await this.getCrucesPorViaje(viajeId, tenantId);
    return cruces.reduce((sum, cruce) => sum + Number(cruce.monto), 0);
  }

  /**
   * Get toll statistics by period
   */
  async getEstadisticasPeajes(
    tenantId: string,
    fechaInicio: Date,
    fechaFin: Date
  ): Promise<{ totalCruces: number; totalMonto: number; promedioPorCruce: number }> {
    const cruces = await this.repository.find({
      where: {
        tenantId,
        fechaCruce: Between(fechaInicio, fechaFin),
      },
    });

    const totalCruces = cruces.length;
    const totalMonto = cruces.reduce((sum, cruce) => sum + Number(cruce.monto), 0);
    const promedioPorCruce = totalCruces > 0 ? totalMonto / totalCruces : 0;

    return { totalCruces, totalMonto, promedioPorCruce };
  }

  /**
   * Get crossings by toll booth
   */
  async getCrucesPorCaseta(
    casetaNombre: string,
    tenantId: string,
    fechaInicio?: Date,
    fechaFin?: Date
  ): Promise<CrucePeaje[]> {
    const where: FindOptionsWhere<CrucePeaje> = {
      tenantId,
      casetaNombre: ILike(`%${casetaNombre}%`),
    };

    if (fechaInicio && fechaFin) {
      where.fechaCruce = Between(fechaInicio, fechaFin);
    }

    return this.repository.find({
      where,
      order: { fechaCruce: 'DESC' },
    });
  }
}

export const crucePeajeService = new CrucePeajeService();
