package jumapacelaya.gob.mx.qr.servicio;

import jakarta.inject.Singleton;
import jumapacelaya.gob.mx.qr.dto.pagoQrDTO;
import jumapacelaya.gob.mx.qr.dto.predioQrDTO;
import jumapacelaya.gob.mx.qr.dto.turnoDTO;
import oracle.jdbc.OraclePreparedStatement;

import javax.sql.DataSource;

import io.micronaut.data.connection.annotation.Connectable;
import io.micronaut.transaction.annotation.Transactional;

import java.sql.*;
import java.util.*;

@Singleton
public class QrServicio {

    private final DataSource dataSource;

    public QrServicio(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    @Transactional
    public List<predioQrDTO> buscarPredios(String nomcte, String calle, String numext) {
        List<predioQrDTO> predios = new ArrayList<>();

        String pNomCliente = nomcte.equalsIgnoreCase("X") ? null : nomcte.toUpperCase();
        String pNomCalle = calle.equalsIgnoreCase("X") ? null : calle.toUpperCase();
        String pNumExt = numext.equalsIgnoreCase("X") ? null : numext.toUpperCase();

        StringBuilder query = new StringBuilder();
        query.append("SELECT DISTINCT predioid, fn_get_direccion(d.direcid) AS direccion, p.direcid, ")
             .append("co.nombre AS colonia, ca.nombre AS calle, c.clienteid, c.nombre, propietarioid, ")
             .append("ctalocaliza, contrato, ctaant, zonafactid, fn_get_tarifa(p.predioid) AS tarifa, ")
             .append("usoid, actividadid, edopredioid, metsumid, serialmed, instalmed ")
             .append("FROM predios p ")
             .append("INNER JOIN clientes c ON p.clienteid = c.clienteid ")
             .append("INNER JOIN direcciones d ON p.direcid = d.direcid ")
             .append("INNER JOIN colonias co USING (coloniaid) ")
             .append("INNER JOIN calles ca USING (coloniaid, calleid) ")
             .append("WHERE ROWNUM <= 10 ");

        if (pNomCliente != null) query.append("AND regexp_like(c.nombre, ?) ");
        if (pNomCalle != null) query.append("AND regexp_like(ca.nombre, ?) ");
        if (pNumExt != null) query.append("AND regexp_like(d.numext, ?) ");
        query.append("ORDER BY predioid");

        try (Connection conn = dataSource.getConnection();
             PreparedStatement ps = conn.prepareStatement(query.toString())) {

            int paramIndex = 1;
            if (pNomCliente != null) ps.setString(paramIndex++, pNomCliente);
            if (pNomCalle != null) ps.setString(paramIndex++, pNomCalle);
            if (pNumExt != null) ps.setString(paramIndex++, pNumExt);

            try (ResultSet rs = ps.executeQuery()) {
                while (rs.next()) {
                    predioQrDTO dto = new predioQrDTO();
                    dto.setPredioid(rs.getInt("predioid"));
                    dto.setDireccion(rs.getString("direccion"));
                    dto.setDirecid(rs.getInt("direcid"));
                    dto.setColonia(rs.getString("colonia"));
                    dto.setCalle(rs.getString("calle"));
                    dto.setClienteid(rs.getInt("clienteid"));
                    dto.setNombre(rs.getString("nombre"));
                    dto.setPropietarioid(rs.getInt("propietarioid"));
                    dto.setCtalocaliza(rs.getString("ctalocaliza"));
                    dto.setContrato(rs.getString("contrato"));
                    dto.setCtaant(rs.getString("ctaant"));
                    dto.setZonafactid(rs.getString("zonafactid"));
                    dto.setTarifa(rs.getString("tarifa"));
                    dto.setUsoid(rs.getString("usoid"));
                    dto.setActividadid(rs.getString("actividadid"));
                    dto.setEdopredioid(rs.getString("edopredioid"));
                    dto.setMetsumid(rs.getString("metsumid"));
                    dto.setSerialmed(rs.getString("serialmed"));
                    dto.setInstalmed(rs.getString("instalmed"));

                    predios.add(dto);
                }
            }

        } catch (SQLException e) {
            throw new RuntimeException("Error al consultar predios: " + e.getMessage(), e);
        }

        return predios;
    }

    @Transactional
    public String buscarINAPAMPorPredio(int predioid) {
        String query = "select inapam from padronpad where predioid = ?";
        try (Connection conn = dataSource.getConnection();
             PreparedStatement ps = conn.prepareStatement(query)) {

            ps.setInt(1, predioid);

            try (ResultSet rs = ps.executeQuery()) {
                if (rs.next()) {
                    return rs.getString("inapam");
                }
            }
        } catch (Exception e) {
            throw new RuntimeException("Error al consultar INAPAM: " + e.getMessage(), e);
        }

        return null;
    }

    @Transactional
    public String generarOtInapam(Long predioid, String direccion, String descripcion) {
        String usuario = "WISJUMAPA";
        String motivoId = "312";

        String query = """
            BEGIN
                operacion.pk_orden.SP_ORDENTRABAJOENC (
                    null, sysdate, null, null, null, null,
                    :usuario, null, null, null,
                    :descripcion, null, null, null, null, null, null,
                    1, sysdate, :predioid, null,
                    :motivoid, :direccion, null, 1,
                    :usuario, null, null, null, null, null, null, null, null, null, null, 1
                );
            END;
        """;

        try (Connection conn = dataSource.getConnection();
            OraclePreparedStatement stmt = (OraclePreparedStatement) conn.prepareStatement(query)) {

            stmt.setStringAtName("descripcion", descripcion);
            stmt.setStringAtName("usuario", usuario);
            stmt.setLongAtName("predioid", predioid);
            stmt.setStringAtName("motivoid", motivoId);
            stmt.setStringAtName("direccion", direccion);

            stmt.execute();

            return "Se generó la inspección de INAPAM al predio " + predioid + " ubicado en la dirección: " + direccion;

        } catch (SQLException e) {
            throw new RuntimeException("Error al generar la inspección INAPAM: " + e.getMessage(), e);
        }
    }

    public Optional<pagoQrDTO> obtenerPagoQr(Long predioid, String pagoid) {
        String query = "SELECT c.nombre AS nomcliente, fn_get_direccion(p.direcid) AS direccionmostrar " +
                       "FROM predios p " +
                       "LEFT JOIN clientes c USING (clienteid) " +
                       "WHERE p.predioid = ?";

        try (Connection conn = dataSource.getConnection();
             PreparedStatement ps = conn.prepareStatement(query)) {

            ps.setLong(1, predioid);

            try (ResultSet rs = ps.executeQuery()) {
                if (rs.next()) {
                    pagoQrDTO dto = new pagoQrDTO();
                    dto.setPredioid(predioid);
                    dto.setPagoid(pagoid);
                    dto.setNomcliente(rs.getString("nomcliente"));
                    dto.setDireccion(rs.getString("direccionmostrar"));
                    return Optional.of(dto);
                }
            }

        } catch (SQLException e) {
            throw new RuntimeException("Error al obtener datos del predio: " + e.getMessage(), e);
        }

        return Optional.empty();
    }

    @Connectable
    public List<turnoDTO> obtenerTurnosPorPunto(int puntoId) {
        List<turnoDTO> turnos = new ArrayList<>();

        String query = """
            SELECT b.descripcion servicio, 'Pendientes: ' || TO_CHAR(COUNT(*)) pendientes
            FROM turnomatico.tmturno a
            INNER JOIN turnomatico.tmservicios b USING (tmservicioid)
            WHERE a.fechaemision >= TRUNC(SYSDATE)
            AND puntoid = ?
            AND entidadid = 1
            AND a.tmturnoid NOT IN (
                SELECT tmturnoid
                FROM turnomatico.tmturnoventanilla
                WHERE fechainicio >= TRUNC(SYSDATE)
                    AND puntoid = ?
                    AND entidadid = 1
            )
            GROUP BY b.descripcion

            UNION

            SELECT r.descripcion, 'Atendiendo: ' || s.letra || '-' || SUBSTR('000' || noturno, -3, 3)
            FROM turnomatico.tmturno a
            INNER JOIN turnomatico.tmservicios s USING (tmservicioid)
            INNER JOIN (
                SELECT MAX(tmturnoid) mturno, c.descripcion
                FROM turnomatico.tmturnoventanilla a
                INNER JOIN turnomatico.tmturno b USING (tmturnoid)
                INNER JOIN turnomatico.tmservicios c USING (tmservicioid)
                WHERE fechainicio >= TRUNC(SYSDATE)
                AND a.puntoid = ?
                AND a.entidadid = 1
                GROUP BY c.descripcion
            ) r ON r.mturno = a.tmturnoid
            ORDER BY 1, 2 DESC
            """;

        try (Connection connection = dataSource.getConnection();
            PreparedStatement ps = connection.prepareStatement(query)) {

            ps.setInt(1, puntoId);
            ps.setInt(2, puntoId);
            ps.setInt(3, puntoId);

            try (ResultSet rs = ps.executeQuery()) {
                while (rs.next()) {
                    turnoDTO dto = new turnoDTO();
                    dto.setServicio(rs.getString(1));
                    dto.setEstado(rs.getString(2));
                    turnos.add(dto);
                }
            }
        } catch (SQLException e) {
            throw new RuntimeException("Error al obtener los turnos: " + e.getMessage(), e);
        }

        return turnos;
    }

}
