package com.starry.admin.api;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import com.starry.admin.common.apitest.ApiTestDataSeeder;
import com.starry.admin.modules.order.module.constant.OrderConstant;
import com.starry.admin.modules.order.module.entity.PlayOrderInfoEntity;
import com.starry.admin.modules.withdraw.entity.EarningsLineEntity;
import com.starry.admin.utils.SecurityUtils;
import com.starry.common.constant.Constants;
import com.starry.common.context.CustomSecurityContextHolder;
import com.starry.common.utils.IdUtils;
import java.math.BigDecimal;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.http.MediaType;

class WxCustomRewardOrderApiTest extends WxCustomOrderApiTestSupport {

    @Test
    void rewardOrderFailsWhenBalanceInsufficient() throws Exception {
        SecurityUtils.setTenantId(ApiTestDataSeeder.DEFAULT_TENANT_ID);
        String remark = "API reward insufficient " + IdUtils.getUuid();
        try {
            setCustomerBalance(BigDecimal.ZERO);
            String customerToken = wxTokenService.createWxUserToken(ApiTestDataSeeder.DEFAULT_CUSTOMER_ID);
            customUserInfoService.updateTokenById(ApiTestDataSeeder.DEFAULT_CUSTOMER_ID, customerToken);

            ensureTenantContext();
            long beforeCount = playOrderInfoService.lambdaQuery()
                    .eq(PlayOrderInfoEntity::getPurchaserBy, ApiTestDataSeeder.DEFAULT_CUSTOMER_ID)
                    .eq(PlayOrderInfoEntity::getPlaceType, OrderConstant.PlaceType.REWARD.getCode())
                    .count();

            String payload = "{" +
                    "\"clerkId\":\"" + ApiTestDataSeeder.DEFAULT_CLERK_ID + "\"," +
                    "\"money\":\"18.00\"," +
                    "\"weiChatCode\":\"apitest-customer-wx\"," +
                    "\"remark\":\"" + remark + "\"" +
                    "}";

            mockMvc.perform(post("/wx/custom/order/reward")
                            .header(USER_HEADER, DEFAULT_USER)
                            .header(TENANT_HEADER, DEFAULT_TENANT)
                            .header(Constants.CUSTOM_USER_LOGIN_TOKEN, Constants.TOKEN_PREFIX + customerToken)
                            .contentType(MediaType.APPLICATION_JSON)
                            .content(payload))
                    .andExpect(status().isOk())
                    .andExpect(jsonPath("$.code").value(998));

            ensureTenantContext();
            long afterCount = playOrderInfoService.lambdaQuery()
                    .eq(PlayOrderInfoEntity::getPurchaserBy, ApiTestDataSeeder.DEFAULT_CUSTOMER_ID)
                    .eq(PlayOrderInfoEntity::getPlaceType, OrderConstant.PlaceType.REWARD.getCode())
                    .count();
            Assertions.assertThat(afterCount).isEqualTo(beforeCount);
        } finally {
            CustomSecurityContextHolder.remove();
        }
    }

    @Test
    // 测试用例：客户指定打赏金额下单时，应即时扣减账户余额、生成已完成的打赏订单并同步收益记录，
    // 同时校验订单归属陪玩师正确且金额与输入一致，确保余额打赏流程闭环。
    void rewardOrderConsumesBalanceAndGeneratesEarnings() throws Exception {
        SecurityUtils.setTenantId(ApiTestDataSeeder.DEFAULT_TENANT_ID);
        try {
            resetCustomerBalance();
            String customerToken = wxTokenService.createWxUserToken(ApiTestDataSeeder.DEFAULT_CUSTOMER_ID);
            customUserInfoService.updateTokenById(ApiTestDataSeeder.DEFAULT_CUSTOMER_ID, customerToken);
            BigDecimal initialBalance = customUserInfoService.getById(ApiTestDataSeeder.DEFAULT_CUSTOMER_ID).getAccountBalance();

            String remark = "API reward order " + IdUtils.getUuid();
            BigDecimal rewardAmount = new BigDecimal("18.75");

            String payload = "{" +
                    "\"clerkId\":\"" + ApiTestDataSeeder.DEFAULT_CLERK_ID + "\"," +
                    "\"money\":\"" + rewardAmount + "\"," +
                    "\"weiChatCode\":\"apitest-customer-wx\"," +
                    "\"remark\":\"" + remark + "\"" +
                    "}";

            mockMvc.perform(post("/wx/custom/order/reward")
                            .header(USER_HEADER, DEFAULT_USER)
                            .header(TENANT_HEADER, DEFAULT_TENANT)
                            .header(Constants.CUSTOM_USER_LOGIN_TOKEN, Constants.TOKEN_PREFIX + customerToken)
                            .contentType(MediaType.APPLICATION_JSON)
                            .content(payload))
                    .andExpect(status().isOk())
                    .andExpect(jsonPath("$.code").value(200))
                    .andExpect(jsonPath("$.data").value("成功"));

            ensureTenantContext();
            PlayOrderInfoEntity order = playOrderInfoService.lambdaQuery()
                    .eq(PlayOrderInfoEntity::getPurchaserBy, ApiTestDataSeeder.DEFAULT_CUSTOMER_ID)
                    .eq(PlayOrderInfoEntity::getRemark, remark)
                    .orderByDesc(PlayOrderInfoEntity::getCreatedTime)
                    .last("limit 1")
                    .one();

            Assertions.assertThat(order).isNotNull();
            Assertions.assertThat(order.getOrderStatus()).isEqualTo(OrderConstant.OrderStatus.COMPLETED.getCode());
            Assertions.assertThat(order.getPlaceType()).isEqualTo(OrderConstant.PlaceType.REWARD.getCode());
            Assertions.assertThat(order.getRewardType()).isEqualTo(OrderConstant.RewardType.BALANCE.getCode());
            Assertions.assertThat(order.getAcceptBy()).isEqualTo(ApiTestDataSeeder.DEFAULT_CLERK_ID);
            Assertions.assertThat(order.getFinalAmount()).isEqualByComparingTo(rewardAmount);

            ensureTenantContext();
            long earningsCount = earningsService.lambdaQuery()
                    .eq(EarningsLineEntity::getOrderId, order.getId())
                    .count();
            Assertions.assertThat(earningsCount).isEqualTo(1);

            BigDecimal expectedBalance = initialBalance.subtract(rewardAmount);
            Assertions.assertThat(customUserInfoService.getById(ApiTestDataSeeder.DEFAULT_CUSTOMER_ID).getAccountBalance())
                    .isEqualByComparingTo(expectedBalance);
        } finally {
            CustomSecurityContextHolder.remove();
        }
    }
}
