package de.gecheckt.pdf.umbenenner.application.service;

import java.util.Objects;

import org.json.JSONException;
import org.json.JSONObject;

import de.gecheckt.pdf.umbenenner.domain.model.AiRawResponse;
import de.gecheckt.pdf.umbenenner.domain.model.AiResponseParsingFailure;
import de.gecheckt.pdf.umbenenner.domain.model.AiResponseParsingResult;
import de.gecheckt.pdf.umbenenner.domain.model.AiResponseParsingSuccess;
import de.gecheckt.pdf.umbenenner.domain.model.ParsedAiResponse;

/**
 * Parses the raw AI response body into a structurally validated {@link ParsedAiResponse}.
 * <p>
 * This parser enforces the technical contract: the AI must respond with exactly one
 * parseable JSON object containing the mandatory fields {@code title} and {@code reasoning},
 * and an optional {@code date} field. Any extra free-text outside the JSON object makes
 * the response technically invalid.
 *
 * <h2>Parsing rules</h2>
 * <ul>
 *   <li>The response body must be a valid JSON object (no arrays, no primitives).</li>
 *   <li>{@code title} must be present and non-empty.</li>
 *   <li>{@code reasoning} must be present (may be empty in degenerate cases, but must exist).</li>
 *   <li>{@code date} is optional; if absent the field is modelled as an empty Optional.</li>
 *   <li>Additional JSON fields are tolerated and silently ignored.</li>
 *   <li>Any free-text outside the outermost JSON object makes the response technically
 *       unacceptable; this is detected by attempting to parse the trimmed body directly
 *       as a JSON object and rejecting inputs that are not pure JSON objects.</li>
 * </ul>
 *
 * <h2>Architecture boundary</h2>
 * <p>
 * Only structural parsing is performed here. Semantic validation (title length,
 * special characters, date format, generic placeholder detection) is the responsibility
 * of {@link AiResponseValidator}.
 */
public final class AiResponseParser {

    private AiResponseParser() {
        // Static utility – no instances
    }

    /**
     * Attempts to parse {@code rawResponse} into a {@link ParsedAiResponse}.
     * <p>
     * Returns {@link AiResponseParsingSuccess} if the response body is a valid JSON object
     * containing the mandatory fields. Returns {@link AiResponseParsingFailure} for any
     * structural problem: non-JSON content, JSON that is not an object, missing mandatory
     * fields, or extra free-text surrounding the JSON object.
     *
     * @param rawResponse the raw AI response body; must not be null
     * @return a parsing result indicating success or failure; never null
     * @throws NullPointerException if {@code rawResponse} is null
     */
    public static AiResponseParsingResult parse(AiRawResponse rawResponse) {
        Objects.requireNonNull(rawResponse, "rawResponse must not be null");

        String body = rawResponse.content();
        if (body == null || body.isBlank()) {
            return new AiResponseParsingFailure("EMPTY_RESPONSE", "AI response body is empty or blank");
        }

        String trimmed = body.trim();

        // Reject if the body does not start with '{' and end with '}' (i.e., not a pure JSON object).
        // This catches responses that embed a JSON object within surrounding prose.
        if (!trimmed.startsWith("{") || !trimmed.endsWith("}")) {
            return new AiResponseParsingFailure(
                    "NOT_JSON_OBJECT",
                    "AI response is not a pure JSON object (contains extra text or is not an object)");
        }

        JSONObject json;
        try {
            json = new JSONObject(trimmed);
        } catch (JSONException e) {
            return new AiResponseParsingFailure("INVALID_JSON", "AI response is not valid JSON: " + e.getMessage());
        }

        // Validate mandatory field: title
        if (!json.has("title") || json.isNull("title")) {
            return new AiResponseParsingFailure("MISSING_TITLE", "AI response missing mandatory field 'title'");
        }
        String title = json.getString("title");
        if (title.isBlank()) {
            return new AiResponseParsingFailure("BLANK_TITLE", "AI response field 'title' is blank");
        }

        // Validate mandatory field: reasoning
        if (!json.has("reasoning") || json.isNull("reasoning")) {
            return new AiResponseParsingFailure("MISSING_REASONING", "AI response missing mandatory field 'reasoning'");
        }
        String reasoning = json.getString("reasoning");

        // Optional field: date
        String dateString = null;
        if (json.has("date") && !json.isNull("date")) {
            dateString = json.getString("date");
        }

        ParsedAiResponse parsed = ParsedAiResponse.of(title, reasoning, dateString);
        return new AiResponseParsingSuccess(parsed);
    }
}
