package com.ruoyi.app.omgpay;

import com.ruoyi.app.omgpay.dto.OmgNotifyField;
import com.ruoyi.app.omgpay.dto.OmgNotifyRequest;
import org.springframework.stereotype.Component;

import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/** Strict parser that preserves the original callback body and every actual field. */
@Component
public class OmgNotifyFormParser {
    static final int MAX_FORM_BYTES = 32 * 1024;
    private static final String FORM_CONTENT_TYPE = "application/x-www-form-urlencoded";
    private static final String OMG_DOCUMENTED_CONTENT_TYPE = "text/html";

    public OmgNotifyRequest parse(byte[] body, String sourceIp, String contentType) {
        byte[] safeBody = body == null ? new byte[0] : body;
        String raw = new String(safeBody, StandardCharsets.UTF_8);
        String normalizedType = contentType == null ? "" : contentType.toLowerCase();
        if (!normalizedType.startsWith(FORM_CONTENT_TYPE)
                && !normalizedType.startsWith(OMG_DOCUMENTED_CONTENT_TYPE)) {
            return invalid(sourceIp, raw, "UNSUPPORTED_CONTENT_TYPE");
        }
        if (safeBody.length == 0) {
            return invalid(sourceIp, raw, "EMPTY_BODY");
        }
        if (safeBody.length > MAX_FORM_BYTES) {
            return invalid(sourceIp, raw, "BODY_TOO_LARGE");
        }
        try {
            return new OmgNotifyRequest(sourceIp, raw, decodeFields(raw), null);
        } catch (IllegalArgumentException exception) {
            return invalid(sourceIp, raw, "MALFORMED_FORM");
        }
    }

    private static List<OmgNotifyField> decodeFields(String raw) {
        List<OmgNotifyField> fields = new ArrayList<>();
        Set<String> names = new HashSet<>();
        for (String pair : raw.split("&", -1)) {
            int separator = pair.indexOf('=');
            if (separator < 1) {
                throw new IllegalArgumentException("field name/value separator missing");
            }
            String name = URLDecoder.decode(pair.substring(0, separator), StandardCharsets.UTF_8);
            String value = URLDecoder.decode(pair.substring(separator + 1), StandardCharsets.UTF_8);
            if (name.isEmpty() || !names.add(name)) {
                throw new IllegalArgumentException("duplicate or empty field name");
            }
            fields.add(new OmgNotifyField(name, value));
        }
        return fields;
    }

    static OmgNotifyRequest invalid(String sourceIp, String raw, String reason) {
        return new OmgNotifyRequest(sourceIp, raw, List.of(), reason);
    }
}
