package tech.easyflow.datacenter.connector.support;

import com.alibaba.fastjson2.JSONObject;
import com.mybatisflex.core.row.Db;
import com.mybatisflex.core.row.Row;
import org.junit.Assert;
import org.junit.Test;
import org.mockito.MockedStatic;
import tech.easyflow.common.entity.LoginAccount;
import tech.easyflow.datacenter.entity.DatacenterTable;
import tech.easyflow.datacenter.entity.DatacenterTableField;
import tech.easyflow.datacenter.meta.entity.DatacenterSource;
import tech.easyflow.datacenter.meta.enums.DatacenterCapability;
import tech.easyflow.datacenter.meta.enums.DatacenterSourceType;

import javax.sql.DataSource;
import java.math.BigInteger;
import java.util.Collections;
import java.util.List;
import java.util.function.Supplier;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyCollection;
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.ArgumentMatchers.anyMap;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.never;

/**
 * 内部动态表幂等批量写入回归测试。
 */
public class AbstractInternalTableConnectorBatchTest {

    /**
     * 验证正常路径按批次写入回执和数据，不退化为逐行 SQL。
     */
    @Test
    public void shouldBatchReceiptsAndRowsOnNormalPath() {
        DatacenterTable table = mock(DatacenterTable.class);
        DatacenterTableField field =
                mock(DatacenterTableField.class);
        org.mockito.Mockito.when(table.getFields())
                .thenReturn(List.of(field));
        org.mockito.Mockito.when(table.getMaterializedTable())
                .thenReturn("tb_internal_test");
        org.mockito.Mockito.when(field.getFieldName())
                .thenReturn("name");
        LoginAccount account = mock(LoginAccount.class);
        org.mockito.Mockito.when(account.getId())
                .thenReturn(BigInteger.ONE);
        org.mockito.Mockito.when(account.getDeptId())
                .thenReturn(BigInteger.ONE);
        org.mockito.Mockito.when(account.getTenantId())
                .thenReturn(BigInteger.ONE);
        JSONObject first = JSONObject.of("name", "first");
        JSONObject second = JSONObject.of("name", "second");

        try (MockedStatic<Db> db = mockStatic(Db.class)) {
            db.when(() -> Db.selectOneByMap(
                            eq("tb_datacenter_write_receipt"),
                            anyMap()))
                    .thenReturn(null);
            db.when(() -> Db.txWithResult(
                            org.mockito.ArgumentMatchers
                                    .<Supplier<Object>>any()))
                    .thenAnswer(invocation -> invocation
                            .<Supplier<?>>getArgument(0)
                            .get());

            boolean written = new TestInternalConnector()
                    .saveRowsIdempotently(
                            new DatacenterSource(),
                            table,
                            List.of(first, second),
                            account,
                            2,
                            "receipt",
                            "hash");

            Assert.assertTrue(written);
            db.verify(() -> Db.insertBatch(
                    eq("tb_datacenter_write_receipt"),
                    anyCollection(),
                    eq(2)));
            db.verify(() -> Db.insertBatch(
                    eq("tb_internal_test"),
                    anyCollection(),
                    eq(2)));
            db.verify(() -> Db.updateBatchById(
                    eq("tb_internal_test"),
                    anyList()), never());
        }
    }

    /**
     * 仅用于测试内部动态表批量协议的最小连接器。
     */
    private static final class TestInternalConnector
            extends AbstractInternalTableConnector {

        /**
         * 创建测试连接器。
         */
        private TestInternalConnector() {
            super(
                    DatacenterSourceType.EXCEL,
                    Collections.<DatacenterCapability>emptySet(),
                    mock(DataSource.class));
        }
    }
}
