package de.avatic.lcc.repositories.premise;

import de.avatic.lcc.model.db.premises.route.RouteNode;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.stereotype.Repository;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

@Repository
public class RouteNodeRepository {


    private final JdbcTemplate jdbcTemplate;

    public RouteNodeRepository(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    public Optional<RouteNode> getById(Integer id) {
        String query = "SELECT * FROM premise_route_node WHERE id = ?";

        List<RouteNode> nodes = jdbcTemplate.query(query, new RouteNodeMapper(), id);

        if(nodes.isEmpty())
            return Optional.empty();
        else
            return Optional.of(nodes.getFirst());
    }

    public void deleteAllById(List<Integer> ids) {
        if (ids == null || ids.isEmpty()) {
            return;
        }

        String placeholders = String.join(",", Collections.nCopies(ids.size(), "?"));
        String sql = "DELETE FROM premise_route_node WHERE id IN (" + placeholders + ")";

        jdbcTemplate.update(sql, ids.toArray(new Object[0]));
    }

    public Integer insert(RouteNode node) {
        String sql = """
                INSERT INTO premise_route_node (name, address, geo_lat, geo_lng, is_destination, is_intermediate,
                is_source, node_id, user_node_id, is_outdated, country_id, external_mapping_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
                """;
        KeyHolder keyHolder = new GeneratedKeyHolder();

        jdbcTemplate.update(connection -> {
            PreparedStatement ps = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
            ps.setString(1, node.getName());
            ps.setString(2, node.getAddress());
            ps.setBigDecimal(3, node.getGeoLat());
            ps.setBigDecimal(4, node.getGeoLng());
            ps.setBoolean(5, Boolean.TRUE.equals(node.getDestination()));
            ps.setBoolean(6, Boolean.TRUE.equals(node.getIntermediate()));
            ps.setBoolean(7, Boolean.TRUE.equals(node.getSource()));
            ps.setObject(8, node.getNodeId(), java.sql.Types.INTEGER);
            ps.setObject(9, node.getUserNodeId(), java.sql.Types.INTEGER);
            ps.setBoolean(10, Boolean.TRUE.equals(node.getOutdated()));
            ps.setObject(11, node.getCountryId(), java.sql.Types.INTEGER);
            ps.setString(12, node.getExternalMappingId());
            return ps;
        }, keyHolder);

        return keyHolder.getKey() != null ? keyHolder.getKey().intValue() : null;
    }

    public Optional<RouteNode> getFromNodeBySectionId(Integer id) {
        String sql = """
                SELECT * FROM premise_route_section LEFT JOIN premise_route_node ON premise_route_node.id = premise_route_section.from_route_node_id WHERE premise_route_section.id = ?
                """;

        var node =  jdbcTemplate.query(sql, new RouteNodeMapper(), id);

        if(node.isEmpty())
            return Optional.empty();

        return Optional.of(node.getFirst());
    }

    public Optional<RouteNode> getToNodeBySectionId(Integer id) {
        String sql = "SELECT * FROM premise_route_section LEFT JOIN premise_route_node ON premise_route_node.id = premise_route_section.to_route_node_id WHERE premise_route_section.id = ?";

        var node =  jdbcTemplate.query(sql, new RouteNodeMapper(), id);

        if(node.isEmpty())
            return Optional.empty();

        return Optional.of(node.getFirst());
    }

    private static class RouteNodeMapper implements RowMapper<RouteNode> {

        @Override
        public RouteNode mapRow(ResultSet rs, int rowNum) throws SQLException {
            RouteNode entity = new RouteNode();

            entity.setId(rs.getInt("id"));
            entity.setName(rs.getString("name"));
            entity.setAddress(rs.getString("address"));

            entity.setGeoLat(rs.getBigDecimal("geo_lat"));
            entity.setGeoLng(rs.getBigDecimal("geo_lng"));

            entity.setDestination(rs.getBoolean("is_destination"));
            entity.setIntermediate(rs.getBoolean("is_intermediate"));
            entity.setSource(rs.getBoolean("is_source"));

            entity.setNodeId(rs.getInt("node_id"));
            entity.setUserNodeId(rs.getInt("user_node_id"));

            entity.setCountryId(rs.getInt("country_id"));

            entity.setOutdated(rs.getBoolean("is_outdated"));

            entity.setExternalMappingId(rs.getString("external_mapping_id"));

            return entity;
        }
    }
}
