package com.ylx.order.mapper;

import org.junit.jupiter.api.Test;

import java.io.InputStream;
import java.nio.charset.StandardCharsets;

import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class AdminOrderMapperXmlTest {

    @Test
    public void adminOrderPageSqlJoinsOrderUserMerchantProjectAndCategory() throws Exception {
        String xml = readMapperXml();

        assertTrue(xml.contains("selectAdminOrderPage"));
        assertTrue(xml.contains("FROM t_order o"));
        assertTrue(xml.contains("LEFT JOIN t_wx_user u ON u.id = CAST(o.user_id AS CHAR)"));
        assertTrue(xml.contains("LEFT JOIN ma_technician mt ON mt.id = o.merchant_id"));
        assertTrue(xml.contains("LEFT JOIN project p ON p.id = o.project_id"));
        assertTrue(xml.contains("LEFT JOIN service_category sc ON sc.id = p.category_id"));
        assertTrue(xml.contains("o.order_no LIKE CONCAT('%', #{dto.orderNo}, '%')"));
        assertTrue(xml.contains("u.c_phone LIKE CONCAT('%', #{dto.userKeyword}, '%')"));
        assertTrue(xml.contains("u.c_nick_name LIKE CONCAT('%', #{dto.userKeyword}, '%')"));
        assertTrue(xml.contains("o.contact_person_name LIKE CONCAT('%', #{dto.userKeyword}, '%')"));
        assertTrue(xml.contains("mt.te_phone LIKE CONCAT('%', #{dto.merchantKeyword}, '%')"));
        assertTrue(xml.contains("o.merchant_nick_name LIKE CONCAT('%', #{dto.merchantKeyword}, '%')"));
        assertTrue(xml.contains("p.category_id = #{dto.categoryId}"));
        assertTrue(xml.contains("o.create_time DESC"));
    }

    @Test
    public void adminOrderRecyclePageSqlUsesSameFiltersAndDeletedOrders() throws Exception {
        String xml = readMapperXml();

        assertTrue(xml.contains("selectAdminOrderRecyclePage"));
        assertTrue(xml.contains("o.is_delete = 1"));
        assertTrue(xml.contains("o.order_no LIKE CONCAT('%', #{dto.orderNo}, '%')"));
        assertTrue(xml.contains("o.create_time &gt;= #{dto.queryStartTime}"));
        assertTrue(xml.contains("o.create_time &lt;= #{dto.queryEndTime}"));
        assertTrue(xml.contains("u.c_phone LIKE CONCAT('%', #{dto.userKeyword}, '%')"));
        assertTrue(xml.contains("u.c_nick_name LIKE CONCAT('%', #{dto.userKeyword}, '%')"));
        assertTrue(xml.contains("o.contact_person_name LIKE CONCAT('%', #{dto.userKeyword}, '%')"));
        assertTrue(xml.contains("p.category_id = #{dto.categoryId}"));
        assertTrue(xml.contains("o.project_name LIKE CONCAT('%', #{dto.projectName}, '%')"));
        assertTrue(xml.contains("mt.te_phone LIKE CONCAT('%', #{dto.merchantKeyword}, '%')"));
        assertTrue(xml.contains("o.merchant_nick_name LIKE CONCAT('%', #{dto.merchantKeyword}, '%')"));
        assertTrue(xml.contains("o.payment_method = #{dto.paymentMethod}"));
        assertTrue(xml.contains("o.status = #{dto.status}"));
        assertTrue(xml.contains("o.merchant_type = #{dto.merchantType}"));
    }

    @Test
    public void serviceCategoryOptionSqlReturnsAllCreatedCategories() throws Exception {
        String xml = readMapperXml();

        assertTrue(xml.contains("selectServiceCategoryOptions"));
        assertTrue(xml.contains("FROM service_category"));
        assertTrue(xml.contains("is_delete = 0"));
        assertTrue(xml.contains("ORDER BY sort ASC, id ASC"));
    }

    @Test
    public void logicDeleteByIdOnlyMarksExistingOrderDeleted() throws Exception {
        String xml = readMapperXml();

        assertTrue(xml.contains("update id=\"logicDeleteById\""));
        assertTrue(xml.contains("UPDATE t_order"));
        assertTrue(xml.contains("is_delete = 1"));
        assertTrue(xml.contains("deleted_time = NOW()"));
        assertTrue(xml.contains("WHERE id = #{id}"));
        assertTrue(xml.contains("AND is_delete = 0"));
    }

    @Test
    public void restoreByIdOnlyRestoresDeletedOrder() throws Exception {
        String xml = readMapperXml();

        assertTrue(xml.contains("update id=\"restoreById\""));
        assertTrue(xml.contains("UPDATE t_order"));
        assertTrue(xml.contains("is_delete = 0"));
        assertTrue(xml.contains("deleted_time = NULL"));
        assertTrue(xml.contains("update_time = NOW()"));
        assertTrue(xml.contains("WHERE id = #{id}"));
        assertTrue(xml.contains("AND is_delete = 1"));
    }

    @Test
    public void refundApplicationSqlReadsOrderChecksPendingAndInsertsApplication() throws Exception {
        String xml = readMapperXml();

        assertTrue(xml.contains("selectRefundApplicationOrderById"));
        assertTrue(xml.contains("o.order_no AS orderNo"));
        assertTrue(xml.contains("COALESCE(u.c_openid, CAST(o.user_id AS CHAR)) AS openId"));
        assertTrue(xml.contains("COALESCE(o.final_amount, 0) AS refundAmount"));
        assertTrue(xml.contains("countPendingRefundApplicationByOrderNo"));
        assertTrue(xml.contains("FROM t_cancel_order_application"));
        assertTrue(xml.contains("audit_status = 0"));
        assertTrue(xml.contains("insertRefundApplication"));
        assertTrue(xml.contains("cancel_order_reason"));
        assertTrue(xml.contains("#{application.cancelOrderReason}"));
    }

    @Test
    public void adminOrderDetailSqlReadsOrderAfterSaleProjectVoucherAndFlow() throws Exception {
        String xml = readMapperXml();

        assertTrue(xml.contains("selectOrderDetailInfoById"));
        assertTrue(xml.contains("o.start_photo AS startPhoto"));
        assertTrue(xml.contains("LEFT JOIN after_sales_service ass"));
        assertTrue(xml.contains("ass_inner.order_id = o.id"));
        assertTrue(xml.contains("selectOrderProjectDetailById"));
        assertTrue(xml.contains("p.merchant_share_ratio AS merchantCommission"));
        assertTrue(xml.contains("selectOrderOperationLogs"));
        assertTrue(xml.contains("FROM t_order_status_flow"));
        assertTrue(xml.contains("WHERE osf.order_id = #{id}"));
        assertTrue(xml.contains("ORDER BY osf.create_time ASC"));
    }

    @Test
    public void dispatchSqlReadsOrderCandidatesUpdatesOrderAndWritesFlow() throws Exception {
        String xml = readMapperXml();

        assertTrue(xml.contains("selectDispatchOrderById"));
        assertTrue(xml.contains("o.status AS status"));
        assertTrue(xml.contains("p.category_id AS categoryId"));
        assertTrue(xml.contains("o.user_latitude AS userLatitude"));
        assertTrue(xml.contains("o.user_longitude AS userLongitude"));
        assertTrue(xml.contains("selectDispatchMerchantCandidates"));
        assertTrue(xml.contains("ST_Distance_Sphere"));
        assertTrue(xml.contains("t.te_area_code = #{query.cityCode}"));
        assertTrue(xml.contains("distance_meters &lt;= #{query.radiusMeters}"));
        assertTrue(xml.contains("ORDER BY candidate.distance_meters ASC"));
        assertTrue(xml.contains("countCurrentDispatchByOrderId"));
        assertTrue(xml.contains("FROM t_order_dispatch"));
        assertTrue(xml.contains("insertOrderDispatch"));
        assertTrue(xml.contains("INSERT INTO t_order_dispatch"));
        assertTrue(xml.contains("updateOrderDispatch"));
        assertTrue(xml.contains("dispatched_time = NOW()"));
        assertTrue(xml.contains("dispatched_status = 1"));
        assertTrue(xml.contains("WHERE id = #{orderId}"));
        assertTrue(xml.contains("AND status = #{statusBefore}"));
        assertTrue(xml.contains("insertOrderStatusFlow"));
        assertTrue(xml.contains("INSERT INTO t_order_status_flow"));
    }

    private String readMapperXml() throws Exception {
        try (InputStream inputStream = getClass().getClassLoader()
                .getResourceAsStream("mapper/order/AdminOrderMapper.xml")) {
            assertNotNull(inputStream, "AdminOrderMapper.xml should exist in test classpath");
            byte[] bytes = new byte[inputStream.available()];
            inputStream.read(bytes);
            return new String(bytes, StandardCharsets.UTF_8);
        }
    }
}
