import { Injectable } from "@nestjs/common";
import { Repository } from "typeorm";
import { Cliente } from "../clientes/entities/cliente.entity";
import { OrdenTrabajo } from "../ots/entities/orden-trabajo.entity";
import { Vehiculo } from "../vehiculos/entities/vehiculo.entity";
import { TenantRepositoryAccessor } from "../tenancy/tenant-repository.accessor";

@Injectable()
export class HistorialService {
  constructor(private readonly tenantAccessor: TenantRepositoryAccessor) {}

  private get clienteRepository(): Repository<Cliente> {
    return this.tenantAccessor.repositoryFor(Cliente);
  }

  private get otRepository(): Repository<OrdenTrabajo> {
    return this.tenantAccessor.repositoryFor(OrdenTrabajo);
  }

  private get vehiculoRepository(): Repository<Vehiculo> {
    return this.tenantAccessor.repositoryFor(Vehiculo);
  }

  async search(term: string) {
    const normalized = String(term || "").trim();
    if (normalized.length < 2) {
      return { q: normalized, clientes: [], vehiculos: [] };
    }

    const like = `%${normalized.toLowerCase()}%`;
    const placaLike = `%${normalized.toUpperCase()}%`;

    const [clientes, vehiculos] = await Promise.all([
      this.clienteRepository
        .createQueryBuilder("cliente")
        .where("LOWER(cliente.tarjeta) LIKE :like", { like })
        .orWhere("LOWER(cliente.nombre) LIKE :like", { like })
        .orWhere("LOWER(cliente.nit) LIKE :like", { like })
        .orWhere("LOWER(cliente.comercial) LIKE :like", { like })
        .orWhere("LOWER(cliente.razonsocial) LIKE :like", { like })
        .orderBy("cliente.nombre", "ASC")
        .limit(8)
        .getMany(),
      this.vehiculoRepository
        .createQueryBuilder("vehiculo")
        .leftJoinAndSelect("vehiculo.tipoVehiculo", "tipoVehiculo")
        .where("vehiculo.placa LIKE :placaLike", { placaLike })
        .orWhere("LOWER(vehiculo.marca) LIKE :like", { like })
        .orWhere("LOWER(vehiculo.modelo) LIKE :like", { like })
        .orderBy("vehiculo.placa", "ASC")
        .limit(8)
        .getMany(),
    ]);

    const clienteRows = await Promise.all(
      clientes.map(async (cliente) => ({
        tarjeta: cliente.tarjeta,
        nombre: cliente.nombre,
        nit: cliente.nit,
        telefono: cliente.telefono,
        celular: cliente.celular,
        totalOts: await this.otRepository.count({
          where: { clienteTarjeta: cliente.tarjeta },
        }),
      })),
    );

    const vehiculoRows = await Promise.all(
      vehiculos.map(async (vehiculo) => {
        const lastOt = await this.otRepository.findOne({
          where: { vehiculoId: vehiculo.id },
          order: { fechaEntrada: "DESC" },
        });

        return {
          id: vehiculo.id,
          placa: vehiculo.placa,
          marca: vehiculo.marca,
          modelo: vehiculo.modelo,
          anio: vehiculo.anio,
          color: vehiculo.color,
          clienteId: vehiculo.clienteId,
          tipoVehiculo: vehiculo.tipoVehiculo?.nombre,
          totalOts: await this.otRepository.count({
            where: { vehiculoId: vehiculo.id },
          }),
          ultimoKm: lastOt?.km || null,
        };
      }),
    );

    return {
      q: normalized,
      clientes: clienteRows,
      vehiculos: vehiculoRows,
    };
  }

  async getHistorialByCliente(clienteTarjeta: string) {
    const requestedTarjeta = String(clienteTarjeta || "").trim();
    const cliente = await this.clienteRepository
      .createQueryBuilder("cliente")
      .where("LOWER(cliente.tarjeta) = :tarjeta", {
        tarjeta: requestedTarjeta.toLowerCase(),
      })
      .getOne();
    const canonicalTarjeta = cliente?.tarjeta || requestedTarjeta;

    const ots = await this.otRepository.find({
      where: { clienteTarjeta: canonicalTarjeta },
      relations: [
        "vehiculo",
        "vehiculo.tipoVehiculo",
        "danos",
        "danos.tipoDano",
        "fotos",
        "firma",
        "cotizaciones",
        "cotizaciones.lineas",
      ],
      order: { fechaEntrada: "DESC" },
    });

    const totalOts = ots.length;
    const totalCotizado = ots.reduce(
      (sum, ot) => sum + Number(ot.cotizaciones?.[0]?.total || 0),
      0,
    );

    const vehiculos = await this.vehiculoRepository.find({
      where: { clienteId: canonicalTarjeta },
      relations: ["tipoVehiculo"],
      order: { placa: "ASC" },
    });

    return {
      cliente,
      clienteTarjeta: canonicalTarjeta,
      totalOts,
      totalCotizado,
      vehiculos,
      ots: ots.map((ot) => this.toHistorialOt(ot)),
    };
  }

  async getHistorialByPlaca(placa: string) {
    const normalizedPlaca = placa.toUpperCase();
    const vehiculo = await this.vehiculoRepository.findOne({
      where: { placa: normalizedPlaca },
      relations: ["tipoVehiculo"],
    });

    if (!vehiculo) {
      return {
        placa: normalizedPlaca,
        vehiculo: null,
        totalOts: 0,
        totalCotizado: 0,
        ots: [],
      };
    }

    const ots = await this.otRepository.find({
      where: { vehiculoId: vehiculo.id },
      relations: [
        "vehiculo",
        "vehiculo.tipoVehiculo",
        "danos",
        "danos.tipoDano",
        "fotos",
        "firma",
        "cotizaciones",
        "cotizaciones.lineas",
      ],
      order: { fechaEntrada: "DESC" },
    });

    const totalCotizado = ots.reduce(
      (sum, ot) => sum + Number(ot.cotizaciones?.[0]?.total || 0),
      0,
    );

    const lastKm = ots.length > 0 ? Number(ots[0].km || 0) : 0;
    const firstKm = ots.length > 0 ? Number(ots[ots.length - 1].km || 0) : 0;

    return {
      placa: normalizedPlaca,
      vehiculo: {
        id: vehiculo.id,
        placa: vehiculo.placa,
        marca: vehiculo.marca,
        modelo: vehiculo.modelo,
        anio: vehiculo.anio,
        motor: vehiculo.motor,
        color: vehiculo.color,
        tipoVehiculo: vehiculo.tipoVehiculo?.nombre,
        clienteId: vehiculo.clienteId,
      },
      totalOts: ots.length,
      totalCotizado,
      kmRecorridos: lastKm - firstKm,
      ultimoKm: lastKm,
      ots: ots.map((ot) => this.toHistorialOt(ot)),
    };
  }

  private toHistorialOt(ot: OrdenTrabajo) {
    const cotizacion = ot.cotizaciones?.[0];
    const fotos = ot.fotos || [];
    const danos = ot.danos || [];
    const firma = ot.firma;

    return {
      id: ot.id,
      numeroOt: ot.numeroOt,
      fechaEntrada: ot.fechaEntrada,
      fechaSalida: ot.fechaSalida,
      estado: ot.estado,
      km: ot.km,
      requerimientoCliente: ot.requerimientoCliente,
      observaciones: ot.observaciones,
      vehiculo: ot.vehiculo
        ? {
            placa: ot.vehiculo.placa,
            marca: ot.vehiculo.marca,
            modelo: ot.vehiculo.modelo,
            anio: ot.vehiculo.anio,
            color: ot.vehiculo.color,
          }
        : null,
      totalCotizacion: Number(cotizacion?.total || 0),
      cotizacion: cotizacion
        ? {
            id: cotizacion.id,
            numeroCotizacion: cotizacion.numeroCotizacion,
            estado: cotizacion.estado,
            subtotal: Number(cotizacion.subtotal || 0),
            iva: Number(cotizacion.iva || 0),
            total: Number(cotizacion.total || 0),
            lineas: (cotizacion.lineas || []).map((linea) => ({
              id: linea.id,
              plu: linea.plu,
              descripcion: linea.descripcion,
              cantidad: Number(linea.cantidad || 0),
              total: Number(linea.total || 0),
              esServicio: Boolean(linea.esServicio),
            })),
          }
        : null,
      evidencia: {
        fotos: fotos.map((foto) => ({
          id: foto.id,
          tipo: foto.tipo,
          url: foto.url,
          descripcion: foto.descripcion,
          createdAt: foto.createdAt,
        })),
        danos: danos.map((dano) => ({
          id: dano.id,
          zona: dano.zona,
          descripcion: dano.descripcion,
          posicionX: dano.posicionX,
          posicionY: dano.posicionY,
          fotoUrl: dano.fotoUrl,
          tipo: dano.tipoDano
            ? {
                id: dano.tipoDano.id,
                nombre: dano.tipoDano.nombre,
                color: dano.tipoDano.color,
              }
            : null,
        })),
        firmaCliente: firma?.firmaCliente
          ? {
              url: firma.firmaCliente,
              nombre: firma.nombreFirmaCliente,
              fecha: firma.fechaFirmaCliente,
            }
          : null,
        firmaRecepcion: firma?.firmaRecepcion
          ? {
              url: firma.firmaRecepcion,
              nombre: firma.nombreFirmaRecepcion,
              fecha: firma.fechaFirmaRecepcion,
            }
          : null,
        pdfEscaner: ot.pdfEscaner || null,
      },
      resumen: {
        totalFotos: fotos.length,
        totalDanos: danos.length,
        tieneFirmas: Boolean(firma?.firmaCliente || firma?.firmaRecepcion),
        tienePdf: Boolean(ot.pdfEscaner),
      },
      accesos: {
        detalle: `/dashboard/ots/${ot.id}`,
        danos: `/dashboard/ots/${ot.id}/danos`,
        fotos: `/dashboard/ots/${ot.id}/fotos`,
        firmas: `/dashboard/ots/${ot.id}/firmas`,
        cotizacion: `/dashboard/ots/${ot.id}/cotizacion`,
      },
    };
  }
}
