package server.logic.ws_protocol.JSON.messages;

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.messages.entyties.Net_SendTestWebPush_Request;
import server.logic.ws_protocol.JSON.messages.entyties.Net_SendTestWebPush_Response;
import server.logic.ws_protocol.JSON.push.WebPushSender;
import server.logic.ws_protocol.JSON.utils.NetExceptionResponseFactory;
import server.logic.ws_protocol.WireCodes;
import shine.db.dao.ActiveSessionsDAO;
import shine.db.entities.ActiveSessionEntry;

import java.util.ArrayList;
import java.util.List;

public class Net_SendTestWebPush_Handler implements JsonMessageHandler {
    @Override
    public Net_Response handle(Net_Request baseRequest, ConnectionContext ctx) throws Exception {
        Net_SendTestWebPush_Request req = (Net_SendTestWebPush_Request) baseRequest;
        if (ctx == null || !ctx.isAuthenticatedUser()) {
            return NetExceptionResponseFactory.error(req, WireCodes.Status.UNVERIFIED, "NOT_AUTHENTICATED", "Требуется авторизация");
        }

        String authLogin = String.valueOf(ctx.getLogin() == null ? "" : ctx.getLogin()).trim();
        String targetLogin = String.valueOf(req.getLogin() == null ? "" : req.getLogin()).trim();
        if (targetLogin.isBlank()) targetLogin = authLogin;

        if (!targetLogin.equalsIgnoreCase(authLogin)) {
            return NetExceptionResponseFactory.error(
                    req,
                    WireCodes.Status.UNVERIFIED,
                    "FORBIDDEN_TARGET_LOGIN",
                    "Разрешена отправка тестового push только для текущего авторизованного пользователя"
            );
        }

        List<ActiveSessionEntry> targets = new ArrayList<>();
        String targetSessionId = String.valueOf(req.getSessionId() == null ? "" : req.getSessionId()).trim();
        if (!targetSessionId.isBlank()) {
            ActiveSessionEntry one = ActiveSessionsDAO.getInstance().getBySessionId(targetSessionId);
            if (one == null || !targetLogin.equalsIgnoreCase(one.getLogin())) {
                return NetExceptionResponseFactory.error(req, WireCodes.Status.BAD_REQUEST, "SESSION_NOT_FOUND", "Сессия для тестового push не найдена");
            }
            targets.add(one);
        } else {
            targets = ActiveSessionsDAO.getInstance().getByLogin(targetLogin);
        }

        String title = String.valueOf(req.getTitle() == null ? "" : req.getTitle()).trim();
        if (title.isBlank()) title = "SHiNE: тестовый push";
        String text = String.valueOf(req.getText() == null ? "" : req.getText()).trim();
        if (text.isBlank()) text = "Тестовое push-уведомление отправлено успешно.";

        int sessionsWithPushConfig = 0;
        int delivered = 0;
        int failed = 0;
        long now = System.currentTimeMillis();

        for (ActiveSessionEntry s : targets) {
            if (isBlank(s.getPushEndpoint()) || isBlank(s.getPushP256dhKey()) || isBlank(s.getPushAuthKey())) {
                continue;
            }
            sessionsWithPushConfig++;
            String payload = "{\"kind\":\"test_push\",\"title\":\"" + jsonEscape(title) + "\",\"text\":\"" + jsonEscape(text) + "\",\"sentAt\":" + now + "}";
            boolean ok = WebPushSender.sendBase64Payload(
                    s.getPushEndpoint(),
                    s.getPushP256dhKey(),
                    s.getPushAuthKey(),
                    payload
            );
            if (ok) delivered++;
            else failed++;
        }

        Net_SendTestWebPush_Response resp = new Net_SendTestWebPush_Response();
        resp.setOp(req.getOp());
        resp.setRequestId(req.getRequestId());
        resp.setStatus(WireCodes.Status.OK);
        resp.setTargetLogin(targetLogin);
        resp.setAttemptedSessions(targets.size());
        resp.setSessionsWithPushConfig(sessionsWithPushConfig);
        resp.setDelivered(delivered);
        resp.setFailed(failed);
        resp.setSentAtMs(now);
        return resp;
    }

    private boolean isBlank(String s) {
        return s == null || s.isBlank();
    }

    private static String jsonEscape(String s) {
        if (s == null) return "";
        StringBuilder out = new StringBuilder();
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            if (c == '\\') out.append("\\\\");
            else if (c == '"') out.append("\\\"");
            else if (c == '\n') out.append("\\n");
            else if (c == '\r') out.append("\\r");
            else if (c == '\t') out.append("\\t");
            else out.append(c);
        }
        return out.toString();
    }
}
