package com.hiveops.guide.service;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.Map;

/**
 * Creates Gitea Bug/Enhancement issues from in-guide feedback. Mirrors the hiveops-browser
 * feedback flow but keeps the token server-side. Reaches Gitea over the public (Cloudflare) route.
 */
@Service
@Slf4j
public class GiteaFeedbackService {

    private final ObjectMapper mapper = new ObjectMapper();
    private final HttpClient http = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(10)).build();

    @Value("${gitea.base-url:https://hiveiq-gitea.directlx.dev}")
    private String baseUrl;
    @Value("${gitea.feedback.token:}")
    private String token;

    private static final String ORG = "hiveiq-src";

    /** area key (= guide module app-prefix, or explicit) → repo name. Default: the guide itself. */
    private static final Map<String, String> REPOS = Map.ofEntries(
            Map.entry("fleet", "hiveops-fleet"), Map.entry("devices", "hiveops-devices"),
            Map.entry("incident", "hiveops-incident"), Map.entry("transactions", "hiveops-transactions"),
            Map.entry("analytics", "hiveops-analytics"), Map.entry("reports", "hiveops-reports"),
            Map.entry("messaging", "hiveops-messaging"), Map.entry("claims", "hiveops-claims"),
            Map.entry("recon", "hiveops-recon"), Map.entry("vault", "hiveops-vault"),
            Map.entry("aria", "hiveops-aria"), Map.entry("msp", "hiveops-msp"),
            Map.entry("dashboard", "hiveops-dashboard"), Map.entry("profile", "hiveops-profile"),
            Map.entry("mobile", "hiveops-mobile"), Map.entry("agent", "hiveops-agent"),
            Map.entry("guide", "hiveops-guide"));

    public record Result(boolean success, Integer number, String url, String error) {}

    public Result create(String type, String area, String title, String description,
                         String module, String email, String role) {
        if (token == null || token.isBlank())
            return new Result(false, null, null, "Feedback is not configured.");
        if (title == null || title.isBlank() || description == null || description.isBlank())
            return new Result(false, null, null, "Title and description are required.");

        String labelName = "enhancement".equalsIgnoreCase(type) ? "Enhancement" : "Bug";
        String repoName = REPOS.getOrDefault(area == null ? "" : area.toLowerCase(), "hiveops-guide");
        String repo = ORG + "/" + repoName;

        try {
            Integer labelId = findLabel(repo, labelName);
            if (labelId == null) labelId = createLabel(repo, labelName);

            String body = description + "\n\n---\n"
                    + "**Submitted via:** guide.bcos.dev\n"
                    + "**Area:** " + repoName + (module != null && !module.isBlank() ? " · " + module : "") + "\n"
                    + "**Reporter:** " + (email == null ? "unknown" : email)
                    + (role != null ? " (" + role + ")" : "") + "\n";

            ObjectNode payload = mapper.createObjectNode();
            payload.put("title", title.trim());
            payload.put("body", body);
            if (labelId != null) payload.putArray("labels").add(labelId.intValue());

            HttpResponse<String> resp = http.send(
                    req(repo, "/issues").POST(HttpRequest.BodyPublishers.ofString(mapper.writeValueAsString(payload))).build(),
                    HttpResponse.BodyHandlers.ofString());
            if (resp.statusCode() >= 200 && resp.statusCode() < 300) {
                JsonNode n = mapper.readTree(resp.body());
                log.info("Feedback issue created: {} #{}", repo, n.path("number").asInt());
                return new Result(true, n.path("number").asInt(), n.path("html_url").asText(), null);
            }
            log.warn("Gitea issue create failed {}: {}", resp.statusCode(), resp.body());
            return new Result(false, null, null, "Gitea returned " + resp.statusCode());
        } catch (Exception e) {
            log.warn("Feedback submit failed: {}", e.getMessage());
            return new Result(false, null, null, e.getMessage());
        }
    }

    private Integer findLabel(String repo, String name) throws Exception {
        HttpResponse<String> r = http.send(req(repo, "/labels?limit=100").GET().build(),
                HttpResponse.BodyHandlers.ofString());
        if (r.statusCode() != 200) return null;
        for (JsonNode l : mapper.readTree(r.body()))
            if (l.path("name").asText().equalsIgnoreCase(name)) return l.path("id").asInt();
        return null;
    }

    private Integer createLabel(String repo, String name) throws Exception {
        ObjectNode p = mapper.createObjectNode();
        p.put("name", name);
        p.put("color", name.equalsIgnoreCase("Enhancement") ? "#a2eeef" : "#d73a4a");
        HttpResponse<String> r = http.send(
                req(repo, "/labels").POST(HttpRequest.BodyPublishers.ofString(mapper.writeValueAsString(p))).build(),
                HttpResponse.BodyHandlers.ofString());
        return (r.statusCode() >= 200 && r.statusCode() < 300) ? mapper.readTree(r.body()).path("id").asInt() : null;
    }

    private HttpRequest.Builder req(String repo, String path) {
        return HttpRequest.newBuilder(URI.create(baseUrl + "/api/v1/repos/" + repo + path))
                .header("Authorization", "token " + token)
                .header("Content-Type", "application/json")
                .timeout(Duration.ofSeconds(20));
    }
}
