package server.logic.ws_protocol.JSON.handlers.channels;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import server.logic.ws_protocol.JSON.ConnectionContext;
import server.logic.ws_protocol.JSON.entyties.Net_Request;
import server.logic.ws_protocol.JSON.entyties.Net_Response;
import server.logic.ws_protocol.JSON.handlers.JsonMessageHandler;
import server.logic.ws_protocol.JSON.handlers.channels.entyties.Net_GetChannelsCounters_Request;
import server.logic.ws_protocol.JSON.handlers.channels.entyties.Net_GetChannelsCounters_Response;
import server.logic.ws_protocol.JSON.utils.NetExceptionResponseFactory;
import server.logic.ws_protocol.WireCodes;
import shine.db.SqliteDbController;
import shine.db.MsgSubType;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

public class Net_GetChannelsCounters_Handler implements JsonMessageHandler {
    private static final Logger log = LoggerFactory.getLogger(Net_GetChannelsCounters_Handler.class);

    @Override
    public Net_Response handle(Net_Request baseRequest, ConnectionContext ctx) {
        Net_GetChannelsCounters_Request req = (Net_GetChannelsCounters_Request) baseRequest;
        if (req.getLogin() == null || req.getLogin().isBlank()) {
            return NetExceptionResponseFactory.error(req, WireCodes.Status.BAD_REQUEST, "bad_fields", "Некорректные поля: login");
        }
        try (Connection c = SqliteDbController.getInstance().getConnection()) {
            String canonicalLogin = ChannelsReadSupport.canonicalLogin(c, req.getLogin().trim());
            if (canonicalLogin == null) {
                return NetExceptionResponseFactory.error(req, 404, "user_not_found", "Пользователь не найден");
            }

            Net_GetChannelsCounters_Response resp = new Net_GetChannelsCounters_Response();
            resp.setOp(req.getOp());
            resp.setRequestId(req.getRequestId());
            resp.setStatus(WireCodes.Status.OK);
            resp.setLogin(canonicalLogin);
            resp.setFeedCount(countFeed(c, canonicalLogin));
            resp.setDialogs100Count(countOwnedByType(c, canonicalLogin, 100));
            resp.setGroupChats200Count(countOwnedByType(c, canonicalLogin, 200));
            resp.setMyChannelsCount(countMyChannels(c, canonicalLogin));
            return resp;
        } catch (Exception e) {
            log.error("GetChannelsCounters failed", e);
            return NetExceptionResponseFactory.error(req, WireCodes.Status.INTERNAL_ERROR, "internal_error", "Внутренняя ошибка сервера");
        }
    }

    private int countFeed(Connection c, String login) throws Exception {
        String sql = """
            SELECT COUNT(*)
            FROM connections_state
            WHERE login = ? COLLATE NOCASE
              AND rel_type = ?
            """;
        try (PreparedStatement ps = c.prepareStatement(sql)) {
            ps.setString(1, login);
            ps.setInt(2, MsgSubType.CONNECTION_FOLLOW);
            try (ResultSet rs = ps.executeQuery()) {
                return rs.next() ? rs.getInt(1) : 0;
            }
        }
    }

    private int countOwnedByType(Connection c, String login, int typeCode) throws Exception {
        String sql = """
            SELECT COUNT(*)
            FROM channel_names_state
            WHERE owner_login = ? COLLATE NOCASE
              AND channel_type_code = ?
            """;
        try (PreparedStatement ps = c.prepareStatement(sql)) {
            ps.setString(1, login);
            ps.setInt(2, typeCode);
            try (ResultSet rs = ps.executeQuery()) {
                return rs.next() ? rs.getInt(1) : 0;
            }
        }
    }

    private int countMyChannels(Connection c, String login) throws Exception {
        String bchCountSql = "SELECT COUNT(*) FROM blockchain_state WHERE login = ? COLLATE NOCASE";
        int stories = 0;
        try (PreparedStatement ps = c.prepareStatement(bchCountSql)) {
            ps.setString(1, login);
            try (ResultSet rs = ps.executeQuery()) {
                stories = rs.next() ? rs.getInt(1) : 0;
            }
        }
        String namedSql = """
            SELECT COUNT(*)
            FROM channel_names_state
            WHERE owner_login = ? COLLATE NOCASE
              AND channel_type_code IN (1,100,200)
            """;
        int named = 0;
        try (PreparedStatement ps = c.prepareStatement(namedSql)) {
            ps.setString(1, login);
            try (ResultSet rs = ps.executeQuery()) {
                named = rs.next() ? rs.getInt(1) : 0;
            }
        }
        return stories + named;
    }
}
