package dev.sonpx.loyalty.mcp.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import dev.sonpx.loyalty.mcp.reward.dto.CampaignRuleSummaryDto;
import dev.sonpx.loyalty.mcp.reward.dto.CampaignSummaryDto;
import dev.sonpx.loyalty.mcp.reward.enums.CampaignType;
import dev.sonpx.loyalty.mcp.reward.enums.RuleType;
import dev.sonpx.loyalty.mcp.reward.model.Campaign;
import dev.sonpx.loyalty.mcp.reward.model.CampaignRule;
import dev.sonpx.loyalty.mcp.reward.model.ReferenceData;
import dev.sonpx.loyalty.mcp.service.CampaignRuleService;
import dev.sonpx.loyalty.mcp.service.CampaignService;
import java.time.LocalDate;
import java.time.LocalDateTime;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;

public class McpResponseSerializationTest {

    private ObjectMapper objectMapper;
    private CampaignService campaignService;
    private CampaignRuleService campaignRuleService;

    @BeforeEach
    void setUp() {
        AppConfig config = new AppConfig();
        objectMapper = config.objectMapper();
        campaignService = new CampaignService(null);
        campaignRuleService = new CampaignRuleService(null);
    }

    @Test
    void testFwAuditFieldsIgnoredAndNullsOmittedInCampaign() throws Exception {
        Campaign campaign = new Campaign();
        campaign.setCampaignId("CMP01");
        campaign.setName("Happy Birthday");
        campaign.setOwnerName("Marketing");
        campaign.setCampaignType(CampaignType.BASE);
        campaign.setRecordNo(100L);
        campaign.setLastUpdateBy("admin");
        campaign.setLastUpdateByName("Admin User");
        campaign.setLastApproveBy("checker");
        campaign.setLastApproveByName("Checker User");

        String json = objectMapper.writeValueAsString(campaign);

        // Audit fields must be ignored
        assertThat(json).doesNotContain("recordNo");
        assertThat(json).doesNotContain("lastUpdateBy");
        assertThat(json).doesNotContain("lastUpdateByName");
        assertThat(json).doesNotContain("lastApproveBy");
        assertThat(json).doesNotContain("lastApproveByName");
        assertThat(json).doesNotContain("lastUpdateDate");
        assertThat(json).doesNotContain("lastApproveDate");

        // Null fields (effectiveFrom, effectiveTo, etc.) must be omitted
        assertThat(json).doesNotContain("effectiveFrom");
        assertThat(json).doesNotContain("effectiveTo");
        assertThat(json).doesNotContain("noOfCustomerTarget");

        // Essential fields present
        assertThat(json).contains("\"campaignId\":\"CMP01\"");
        assertThat(json).contains("\"name\":\"Happy Birthday\"");
    }

    @Test
    void testCampaignSummaryDtoMappingAndSerialization() throws Exception {
        Campaign campaign = new Campaign();
        campaign.setCampaignId("CMP02");
        campaign.setName("Summer Sale");
        campaign.setOwnerName("Sales");
        campaign.setCampaignType(CampaignType.TACTICAL);
        campaign.setEffectiveFrom(LocalDate.of(2026, 6, 1));
        campaign.setEffectiveTo(LocalDate.of(2026, 8, 31));
        campaign.setNumOfRule(3);

        CampaignSummaryDto dto = campaignService.toSummaryDto(campaign);
        String json = objectMapper.writeValueAsString(dto);

        assertThat(json).contains("\"campaignId\":\"CMP02\"");
        assertThat(json).contains("\"name\":\"Summer Sale\"");
        assertThat(json).contains("\"ownerName\":\"Sales\"");
        assertThat(json).contains("\"numOfRule\":3");
        assertThat(json).doesNotContain("description"); // Null field omitted
        assertThat(json).doesNotContain("targetAtv");
    }

    @Test
    void testCampaignRuleSummaryDtoMappingAndSerialization() throws Exception {
        CampaignRule rule = new CampaignRule();
        rule.setRuleId("R01");
        rule.setRuleName("Bonus Point Rule");
        rule.setRuleType(RuleType.AWARD);
        rule.setCampaignId(new ReferenceData("CMP01", "Happy Birthday Campaign"));
        rule.setPoolId(new ReferenceData("POOL01", "Main Point Pool"));
        rule.setEffectiveFrom(LocalDateTime.of(2026, 1, 1, 0, 0));

        CampaignRuleSummaryDto dto = campaignRuleService.toSummaryDto(rule);
        String json = objectMapper.writeValueAsString(dto);

        assertThat(json).contains("\"ruleId\":\"R01\"");
        assertThat(json).contains("\"ruleName\":\"Bonus Point Rule\"");
        assertThat(json).contains("\"ruleType\":\"AWD\"");
        assertThat(json).contains("\"code\":\"CMP01\"");
        assertThat(json).doesNotContain("effectiveTo"); // Null field omitted
        assertThat(json).doesNotContain("campaignFormulaOne");
        assertThat(json).doesNotContain("campaignFormulaSetting");
    }

    @Test
    void testSanitizeFormulasInCampaignRule() throws Exception {
        CampaignRule rule = new CampaignRule();
        rule.setRuleId("R02");
        rule.setRuleName("Double Points");

        // Formulas with all nulls
        rule.setCampaignFormulaOne(new dev.sonpx.loyalty.mcp.reward.model.CampaignFormulaOne());
        rule.setCampaignFormulaTwo(new dev.sonpx.loyalty.mcp.reward.model.CampaignFormulaTwo());

        campaignRuleService.sanitizeFormulas(rule);

        assertThat(rule.getCampaignFormulaOne()).isNull();
        assertThat(rule.getCampaignFormulaTwo()).isNull();

        String json = objectMapper.writeValueAsString(rule);
        assertThat(json).doesNotContain("campaignFormulaOne");
        assertThat(json).doesNotContain("campaignFormulaTwo");
    }
}
