package com.ruoyi.web.modules.farming.service.impl;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.web.modules.farming.TechResourceTestSamples;
import com.ruoyi.web.modules.farming.domain.BizTechResource;
import com.ruoyi.web.modules.farming.mapper.BizTechResourceMapper;
import com.ruoyi.web.modules.farming.support.TechResourceAccountAssigner;
import com.ruoyi.web.modules.farming.support.TechResourceReferenceChecker;
import com.ruoyi.web.modules.farming.support.TechResourceRules;
import com.ruoyi.web.modules.farming.support.TechResourceTypeValidator;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
@DisplayName("BizTechResourceServiceImpl")
class BizTechResourceServiceImplTest
{
    @Mock
    private BizTechResourceMapper mapper;

    @Mock
    private TechResourceReferenceChecker referenceChecker;

    @Mock
    private TechResourceAccountAssigner accountAssigner;

    @Mock
    private TechResourceTypeValidator techResourceTypeValidator;

    @InjectMocks
    private BizTechResourceServiceImpl service;

    @Test
    @DisplayName("新增落库未发布")
    void insert()
    {
        when(mapper.insertBizTechResource(any())).thenReturn(1);
        assertEquals(1, service.insertBizTechResource(TechResourceTestSamples.sampleExpertDraft()));
        verify(mapper).insertBizTechResource(argThat(r ->
                TechResourceRules.PUBLISH_STATUS_DRAFT == r.getPublishStatus()
                        && TechResourceRules.ACCOUNT_ASSIGNED_NO == r.getAccountAssigned()
                        && TechResourceRules.DEFAULT_EXPERT_RATING.equals(r.getExpertRating())));
    }

    @Test
    @DisplayName("新增非专家不设评分")
    void insertNonExpertRatingNull()
    {
        when(mapper.insertBizTechResource(any())).thenReturn(1);
        assertEquals(1, service.insertBizTechResource(TechResourceTestSamples.sampleAchievementDraft()));
        verify(mapper).insertBizTechResource(argThat(r -> r.getExpertRating() == null));
    }

    @Test
    @DisplayName("已发布不可改")
    void updatePublishedBlocked()
    {
        when(mapper.selectBizTechResourceById(2L)).thenReturn(TechResourceTestSamples.samplePublishedExpert());
        BizTechResource in = TechResourceTestSamples.sampleExpertDraft();
        in.setId(2L);
        assertThrows(ServiceException.class, () -> service.updateBizTechResource(in));
        verify(mapper, never()).updateBizTechResource(any());
    }

    @Test
    @DisplayName("发布清空下架时间")
    void publish()
    {
        BizTechResource db = TechResourceTestSamples.sampleExpertDraft();
        db.setId(1L);
        db.setOfflineTime(new java.util.Date());
        db.setServiceWeekdays("1,2,3,4,5");
        when(mapper.selectBizTechResourceById(1L)).thenReturn(db);
        when(mapper.updateBizTechResource(any())).thenReturn(1);
        assertEquals(1, service.publish(1L));
        verify(mapper).updateBizTechResource(argThat(r ->
                TechResourceRules.PUBLISH_STATUS_PUBLISHED == r.getPublishStatus()
                        && r.getOfflineTime() == null));
    }

    @Test
    @DisplayName("下架保留发布时间")
    void offline()
    {
        when(mapper.selectBizTechResourceById(2L)).thenReturn(TechResourceTestSamples.samplePublishedExpert());
        when(mapper.updateBizTechResource(any())).thenReturn(1);
        assertEquals(1, service.offline(2L));
        verify(mapper).updateBizTechResource(argThat(r ->
                TechResourceRules.PUBLISH_STATUS_DRAFT == r.getPublishStatus()
                        && r.getOfflineTime() != null
                        && r.getPublishTime() != null));
    }

    @Test
    @DisplayName("删除有关联拒绝")
    void deleteWithReference()
    {
        BizTechResource db = TechResourceTestSamples.sampleExpertDraft();
        db.setId(5L);
        db.setDelFlag(TechResourceRules.DEL_FLAG_NORMAL);
        when(mapper.selectBizTechResourceByIdAny(5L)).thenReturn(db);
        when(referenceChecker.hasReference(5L)).thenReturn(true);
        assertThrows(ServiceException.class, () -> service.deleteBizTechResourceByIds(new Long[] { 5L }, "tester"));
        verify(mapper, never()).logicDeleteBizTechResourceByIds(any(), any());
    }

    @Test
    @DisplayName("删除已分配联动删账号")
    void deleteRemovesLinkedAccount()
    {
        BizTechResource db = TechResourceTestSamples.sampleExpertDraft();
        db.setId(6L);
        db.setDelFlag(TechResourceRules.DEL_FLAG_NORMAL);
        db.setAccountAssigned(TechResourceRules.ACCOUNT_ASSIGNED_YES);
        db.setSysUserId(88L);
        when(mapper.selectBizTechResourceByIdAny(6L)).thenReturn(db);
        when(referenceChecker.hasReference(6L)).thenReturn(false);
        doNothing().when(accountAssigner).deleteLinkedAccount(db);
        when(mapper.logicDeleteBizTechResourceByIds(any(), eq("tester"))).thenReturn(1);
        assertEquals(1, service.deleteBizTechResourceByIds(new Long[] { 6L }, "tester"));
        verify(accountAssigner).deleteLinkedAccount(db);
    }

    @Test
    @DisplayName("专家分配账号")
    void assignAccount()
    {
        BizTechResource db = TechResourceTestSamples.sampleExpertDraft();
        db.setId(1L);
        when(mapper.selectBizTechResourceById(1L)).thenReturn(db);
        SysUser user = new SysUser();
        user.setUserId(100L);
        user.setUserName("zzj1");
        when(accountAssigner.createAccount(any(), any())).thenReturn(user);
        when(mapper.updateBizTechResource(any())).thenReturn(1);
        assertEquals(1, service.assignAccount(1L, "admin"));
        verify(mapper).updateBizTechResource(argThat(r ->
                TechResourceRules.ACCOUNT_ASSIGNED_YES == r.getAccountAssigned()));
    }
}
