package com.xyw.console.asset.service;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.verify;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xyw.console.asset.dto.WecomAccountPageQuery;
import com.xyw.console.asset.dto.WecomAccountPageResponse;
import com.xyw.console.asset.dto.WecomAccountResponse;
import com.xyw.console.asset.dto.WecomAccountSaveRequest;
import com.xyw.console.asset.entity.AssetDeviceEntity;
import com.xyw.console.asset.entity.CompanyPersonEntity;
import com.xyw.console.asset.entity.CompanyProfileEntity;
import com.xyw.console.asset.entity.PhoneAssetEntity;
import com.xyw.console.asset.entity.WecomAccountEntity;
import com.xyw.console.asset.mapper.AssetDeviceMapper;
import com.xyw.console.asset.mapper.CompanyPersonMapper;
import com.xyw.console.asset.mapper.CompanyProfileMapper;
import com.xyw.console.asset.mapper.PhoneAssetMapper;
import com.xyw.console.asset.mapper.WecomAccountMapper;
import java.time.LocalDateTime;
import java.util.List;
import org.junit.jupiter.api.Test;

class WecomAccountServiceTest {

  /**
   * 代码作用（白话）：证明企微列表会把当前页关联 ID 转成可读名称，同时保留 ID 且不产生删除标记字段。
   * 关联文件：WecomAccountService.java、WecomAccountResponse.java、WecomAccountMapper.java。
   * 关联逻辑（调用链/数据流）：分页请求 -> Service 查询企微及关联资产 -> Response -> 前端表格。
   */
  @Test
  void returnsReadableRelatedNamesForTheCurrentWecomAccountPage() {
    WecomAccountMapper wecomMapper = mock(WecomAccountMapper.class);
    CompanyProfileMapper companyProfileMapper = mock(CompanyProfileMapper.class);
    PhoneAssetMapper phoneAssetMapper = mock(PhoneAssetMapper.class);
    AssetDeviceMapper assetDeviceMapper = mock(AssetDeviceMapper.class);
    CompanyPersonMapper companyPersonMapper = mock(CompanyPersonMapper.class);
    when(wecomMapper.selectPage(any(), any())).thenReturn(wecomPage());
    when(companyProfileMapper.selectList(any())).thenReturn(List.of(companyProfile()));
    when(phoneAssetMapper.selectList(any())).thenReturn(List.of(phoneAsset()));
    when(assetDeviceMapper.selectList(any())).thenReturn(List.of(device()));
    when(companyPersonMapper.selectList(any())).thenReturn(List.of(operatorPerson()));

    WecomAccountPageResponse result = new WecomAccountService(
        wecomMapper, companyProfileMapper, phoneAssetMapper, assetDeviceMapper, companyPersonMapper)
        .page(new WecomAccountPageQuery(null, null, null, null, null, null, null));

    WecomAccountResponse record = result.records().get(0);
    assertEquals(1L, record.id());
    assertEquals("示例科技有限公司", record.companyProfileName());
    assertEquals(10L, record.companyProfileId());
    assertEquals("13812345678", record.phoneNumber());
    assertEquals(20L, record.phoneAssetId());
    assertEquals("iPhone 15", record.deviceName());
    assertEquals(30L, record.deviceId());
    assertEquals("王五", record.operatorPersonName());
    assertEquals(40L, record.operatorPersonId());
    assertEquals("张三", record.realNameOwner());
    assertEquals(1, result.page());
    assertEquals(20, result.size());
  }

  /**
   * 代码作用（白话）：证明关联 ID 没有对应资产时，企微记录仍能返回且名称为空。
   * 关联文件：WecomAccountService.java、WecomAccountResponse.java、WecomAccountMapper.java。
   * 关联逻辑（调用链/数据流）：企微记录含关联 ID -> 批量查询无匹配 -> Response 保留 ID 与空名称。
   */
  @Test
  void keepsRelatedIdsWhenTheirNamesCannotBeResolved() {
    WecomAccountMapper wecomMapper = mock(WecomAccountMapper.class);
    CompanyProfileMapper companyProfileMapper = mock(CompanyProfileMapper.class);
    PhoneAssetMapper phoneAssetMapper = mock(PhoneAssetMapper.class);
    AssetDeviceMapper assetDeviceMapper = mock(AssetDeviceMapper.class);
    CompanyPersonMapper companyPersonMapper = mock(CompanyPersonMapper.class);
    when(wecomMapper.selectPage(any(), any())).thenReturn(wecomPage());
    when(companyProfileMapper.selectList(any())).thenReturn(List.of());
    when(phoneAssetMapper.selectList(any())).thenReturn(List.of());
    when(assetDeviceMapper.selectList(any())).thenReturn(List.of());
    when(companyPersonMapper.selectList(any())).thenReturn(List.of());

    WecomAccountResponse record = new WecomAccountService(
        wecomMapper, companyProfileMapper, phoneAssetMapper, assetDeviceMapper, companyPersonMapper)
        .page(new WecomAccountPageQuery(1, 20, null, null, null, null, null)).records().get(0);

    assertEquals(10L, record.companyProfileId());
    assertNull(record.companyProfileName());
    assertEquals(20L, record.phoneAssetId());
    assertNull(record.phoneNumber());
    assertEquals(30L, record.deviceId());
    assertNull(record.deviceName());
    assertEquals(40L, record.operatorPersonId());
    assertNull(record.operatorPersonName());
  }

  /**
   * 代码作用（白话）：构造一页正常企微资产记录，供关联名称转换场景使用。
   * 关联文件：WecomAccountEntity.java、WecomAccountService.java。
   * 关联逻辑（调用链/数据流）：测试记录 -> Mapper 分页结果 -> Service -> Response。
   */
  private Page<WecomAccountEntity> wecomPage() {
    WecomAccountEntity entity = new WecomAccountEntity();
    entity.setId(1L);
    entity.setWecomName("张三");
    entity.setWecomAlias("销售一组");
    entity.setWecomAccount("zhangsan");
    entity.setCompanyProfileId(10L);
    entity.setPhoneAssetId(20L);
    entity.setRealNameOwner("张三");
    entity.setRealNameOwnerStatus("已实名");
    entity.setGender("男");
    entity.setDeviceId(30L);
    entity.setOperatorPersonId(40L);
    entity.setCreateTime(LocalDateTime.of(2026, 7, 31, 10, 0));
    entity.setUpdateTime(LocalDateTime.of(2026, 7, 31, 11, 0));
    entity.setDeleteTime(0L);
    Page<WecomAccountEntity> page = new Page<>(1, 20);
    page.setRecords(List.of(entity));
    page.setTotal(1L);
    return page;
  }

  /**
   * 代码作用（白话）：构造公司档案名称，验证公司 ID 能转成页面可读名称。
   * 关联文件：CompanyProfileEntity.java、WecomAccountService.java。
   * 关联逻辑（调用链/数据流）：companyProfileId -> CompanyProfileMapper -> companyProfileName。
   */
  private CompanyProfileEntity companyProfile() {
    CompanyProfileEntity entity = new CompanyProfileEntity();
    entity.setId(10L);
    entity.setCompanyName("示例科技有限公司");
    return entity;
  }

  /**
   * 代码作用（白话）：构造手机号资产名称，验证手机号资产 ID 能转成手机号。
   * 关联文件：PhoneAssetEntity.java、WecomAccountService.java。
   * 关联逻辑（调用链/数据流）：phoneAssetId -> PhoneAssetMapper -> phoneNumber。
   */
  private PhoneAssetEntity phoneAsset() {
    PhoneAssetEntity entity = new PhoneAssetEntity();
    entity.setId(20L);
    entity.setPhoneNumber("13812345678");
    return entity;
  }

  /**
   * 代码作用（白话）：构造设备名称，验证设备 ID 能转成设备名称。
   * 关联文件：AssetDeviceEntity.java、WecomAccountService.java。
   * 关联逻辑（调用链/数据流）：deviceId -> AssetDeviceMapper -> deviceName。
   */
  private AssetDeviceEntity device() {
    AssetDeviceEntity entity = new AssetDeviceEntity();
    entity.setId(30L);
    entity.setDeviceName("iPhone 15");
    return entity;
  }

  /**
   * 代码作用（白话）：构造经办人名称，验证经办人 ID 能转成页面可读人员名称。
   * 关联文件：CompanyPersonEntity.java、WecomAccountService.java。
   * 关联逻辑（调用链/数据流）：operatorPersonId -> CompanyPersonMapper -> operatorPersonName。
   */
  private CompanyPersonEntity operatorPerson() {
    CompanyPersonEntity entity = new CompanyPersonEntity();
    entity.setId(40L);
    entity.setPersonName("王五");
    return entity;
  }

  /** Code purpose (plain language): proves an entered existing number is reused and marked as an existing link. Related files: WecomAccountService.java, WecomAccountSaveRequest.java. Data flow: create request -> existing phone -> WeCom response. */
  @Test
  void createsWithAnExistingPhoneAsset() {
    WecomAccountMapper wecomMapper = mock(WecomAccountMapper.class); PhoneAssetMapper phoneMapper = mock(PhoneAssetMapper.class);
    PhoneAssetEntity phone = phoneAsset(); when(phoneMapper.selectOne(any())).thenReturn(phone); when(wecomMapper.insert(any(WecomAccountEntity.class))).thenReturn(1);
    WecomAccountResponse result = new WecomAccountService(wecomMapper, mock(CompanyProfileMapper.class), phoneMapper, mock(AssetDeviceMapper.class), mock(CompanyPersonMapper.class)).create(new WecomAccountSaveRequest("测试企微", "别名", null, null, "13812345678", null, null, null, null));
    assertEquals(20L, result.phoneAssetId()); assertEquals("EXISTING", result.phoneLinkMode());
  }

  /** Code purpose (plain language): proves a missing number creates an external phone asset and traces it back to the WeCom record. Related files: WecomAccountService.java, PhoneAssetEntity.java. Data flow: create request -> new phone -> new WeCom -> source update. */
  @Test
  void createsAnExternalPhoneAssetForANewNumber() {
    WecomAccountMapper wecomMapper = mock(WecomAccountMapper.class); PhoneAssetMapper phoneMapper = mock(PhoneAssetMapper.class);
    when(phoneMapper.selectOne(any())).thenReturn(null); when(phoneMapper.insert(any(PhoneAssetEntity.class))).thenAnswer(call -> { ((PhoneAssetEntity) call.getArgument(0)).setId(70L); return 1; }); when(wecomMapper.insert(any(WecomAccountEntity.class))).thenAnswer(call -> { ((WecomAccountEntity) call.getArgument(0)).setId(80L); return 1; });
    WecomAccountResponse result = new WecomAccountService(wecomMapper, mock(CompanyProfileMapper.class), phoneMapper, mock(AssetDeviceMapper.class), mock(CompanyPersonMapper.class)).create(new WecomAccountSaveRequest("测试企微", null, null, null, "13912345678", null, null, null, null));
    assertEquals("CREATED", result.phoneLinkMode()); verify(phoneMapper).updateById(any(PhoneAssetEntity.class));
  }}
