package com.cf.imes.module.system.controller.admin.organ;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import com.cf.imes.framework.common.exception.ServiceException;
import com.cf.imes.framework.common.pojo.CommonResult;
import com.cf.imes.framework.common.pojo.PageParam;
import com.cf.imes.framework.common.pojo.PageResult;
import com.cf.imes.framework.common.util.i18n.core.util.I18nUtils;
import com.cf.imes.framework.common.util.object.BeanUtils;
import com.cf.imes.framework.excel.core.util.ExcelUtils;
import com.cf.imes.framework.operatelog.core.annotations.OperateLog;
import com.cf.imes.framework.security.core.util.SecurityFrameworkUtils;
import com.cf.imes.module.system.api.user.dto.OrganAdminUserRespDTO;
import com.cf.imes.module.system.controller.admin.funds.delay.vo.ProductDelayRespVO;
import com.cf.imes.module.system.controller.admin.funds.organamount.vo.OrganProductOverviewRespVO;
import com.cf.imes.module.system.controller.admin.organ.vo.organ.*;
import com.cf.imes.module.system.dal.dataobject.funds.purchase.PurchaseRecordDO;
import com.cf.imes.module.system.dal.dataobject.organ.OrganizationDO;
import com.cf.imes.module.system.enums.pay.DurationUnitEnum;
import com.cf.imes.module.system.enums.pay.PurchaseRecordStatusEnum;
import com.cf.imes.module.system.service.funds.delay.ProductDelayService;
import com.cf.imes.module.system.service.funds.organamount.OrganAmountService;
import com.cf.imes.module.system.service.funds.purchase.PurchaseService;
import com.cf.imes.module.system.service.organ.OrganService;
import com.cf.imes.module.system.service.user.AdminUserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.groups.Default;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import jakarta.annotation.Resource;
import jakarta.annotation.security.PermitAll;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

import static cn.hutool.core.date.DatePattern.NORM_DATE_FORMATTER;
import static com.cf.imes.framework.common.pojo.CommonResult.success;
import static com.cf.imes.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
import static com.cf.imes.module.system.enums.ErrorCodeConstants.ORGAN_EXPIRETIME_PRODUCTID_LACK;
import static com.cf.imes.module.system.enums.ErrorCodeConstants.ORGAN_NOT_EXISTS;

@Tag(name = "管理后台 - 组织")
@RestController
@RequestMapping("/system/organ")
public class OrganController {

    @Resource
    private OrganService organService;

    @Resource
    private AdminUserService adminUserService;

    @Resource
    private PurchaseService purchaseService;

    @Resource
    private ProductDelayService productDelayService;

    @Resource
    private OrganAmountService organAmountService;

    @Resource
    private I18nUtils i18nUtils;

    @GetMapping("/get-id-by-name")
    @PermitAll
    @Operation(summary = "使用组织名，获得组织编号", description = "登录界面，根据用户的组织名，获得组织编号")
    @Parameter(name = "name", description = "组织名", required = true, example = "1024")
    public CommonResult<Long> getOrganIdByName(@RequestParam("name") String name) {
        OrganizationDO organizationDO = organService.getOrganByName(name);
        return success(organizationDO != null ? organizationDO.getId() : null);
    }

    @GetMapping("/get-by-website")
    @PermitAll
    @Operation(summary = "使用域名，获得组织信息", description = "登录界面，根据用户的域名，获得组织信息")
    @Parameter(name = "website", description = "域名", required = true, example = "www.cf.com")
    public CommonResult<OrganSimpleRespVO> getOrganByWebsite(@RequestParam("website") String website) {
        OrganizationDO organizationDO = organService.getOrganByWebsite(website);
        return success(BeanUtils.toBean(organizationDO, OrganSimpleRespVO.class));
    }

    @PostMapping("/create")
    @Operation(summary = "创建组织")
    @PreAuthorize("@ss.hasPermission('organizationLIst:create')")
    public CommonResult<Long> createOrgan(@Validated({OrganSaveCreateGroup.class, Default.class}) @RequestBody OrganSaveReqVO createReqVO) {
        return success(organService.createOrgan(createReqVO));
    }

    @PutMapping("/update")
    @Operation(summary = "更新组织")
    @PreAuthorize("@ss.hasPermission('organizationLIst:update')")
    public CommonResult<Boolean> updateOrgan(@Validated({OrganSaveUpdateGroup.class, Default.class}) @RequestBody OrganSaveReqVO updateReqVO) {
        organService.updateOrgan(updateReqVO);
        return success(true);
    }

    @PostMapping("/status")
    @Operation(summary = "更新组织状态")
    @PreAuthorize("@ss.hasPermission('organizationLIst:update')")
    public CommonResult<Boolean> updateOrganStatus(@Valid @RequestBody OrganUpdateStatusReqVO updateReqVO) {
        organService.updateOrganStatus(updateReqVO);
        return success(true);
    }

    @DeleteMapping("/delete")
    @Operation(summary = "删除组织")
    @Parameter(name = "id", description = "编号", required = true, example = "1024")
    @PreAuthorize("@ss.hasPermission('organizationLIst:delete')")
    public CommonResult<Boolean> deleteOrgan(@RequestParam("id") Long id) {
        organService.deleteOrgan(id);
        return success(true);
    }

    @GetMapping("/get")
    @Operation(summary = "查询组织信息")
    @Parameter(name = "id", description = "编号", required = true, example = "1024")
    public CommonResult<OrganRespVO> getOrgan(@RequestParam("id") Long id) {
        OrganizationDO organ = organService.getOrgan(id);
        if (ObjectUtil.isNull(organ)) {
            throw new ServiceException(ORGAN_NOT_EXISTS);
        }
        OrganRespVO bean = BeanUtils.toBean(organ, OrganRespVO.class);

        Long organId = bean.getId();
        // 查询当次列表组织下的所有产品的首购记录
        List<OrganPagePurchaseRespVO> orgPurchaseList = BeanUtil.copyToList(
                purchaseService.getOrgPurchaseList(Set.of(organId)).stream().filter(p -> p.getInitial()).collect(Collectors.toList()), OrganPagePurchaseRespVO.class
        );
        // 查询购买记录下的延期记录
        orgPurchaseList.forEach(p -> {
            p.setPrice(p.getTotalAmount());
            List<ProductDelayRespVO> delayRecordsByPurchaseId = productDelayService.getRecordsByPurchaseId(p.getId(), organId);
            if (CollUtil.isNotEmpty(delayRecordsByPurchaseId)) {
                // 产品有效时间展示为第一项的计算延期时间
                p.setEndTime(delayRecordsByPurchaseId.get(0).getDelayTime());
                // 延期时长展示为延期记录的时长+单位，用顿号分隔
                p.setDelayDuration(delayRecordsByPurchaseId.stream().map(m -> m.getDelayDuration() + i18nUtils.getMessage(DurationUnitEnum.getDesc(m.getDelayDurationUnit()))).collect(Collectors.joining("、")));
            }
        });
        bean.setOrganPurchaseList(orgPurchaseList);
        return success(bean);
    }

    @GetMapping("/product/expireTime")
    @Operation(summary = "查询组织产品有效时间")
    @Parameter(name = "id", description = "编号", required = true, example = "1024")
    @Parameter(name = "productId", description = "产品编号", required = true, example = "1024")
    public CommonResult<String> getOrganProductExpireTime(@RequestParam("id") Long id, @RequestParam(value = "productId", required = false) Long productId) {
        String expireTime = "";
        OrganizationDO organ = organService.getOrgan(id);
        if (ObjectUtil.isNull(organ)) {
            throw new ServiceException(ORGAN_NOT_EXISTS);
        }
        OrganRespVO bean = BeanUtils.toBean(organ, OrganRespVO.class);
        // 是否管理端，管理端要选了产品后展示有效时间
        boolean manageEndPoint = SecurityFrameworkUtils.isManageEndPoint();
        if (manageEndPoint) {
            if (ObjectUtil.isNull(productId)) {
                throw new ServiceException(ORGAN_EXPIRETIME_PRODUCTID_LACK);
            }
        } else {
            // 生产端从token中获取产品
            productId = SecurityFrameworkUtils.getProductId();
        }

        Long organId = bean.getId();
        // 查询当前列表组织下的选择productId产品的记录
        Long finalProductId = productId;
        List<OrganPagePurchaseRespVO> orgPurchaseList = BeanUtil.copyToList(
                purchaseService.getOrgPurchaseList(Set.of(organId)).stream().filter(p -> finalProductId.equals(p.getProductId())).collect(Collectors.toList()), OrganPagePurchaseRespVO.class
        );

        if (CollUtil.isNotEmpty(orgPurchaseList)) {
            OrganPagePurchaseRespVO currentProduct = orgPurchaseList.get(0);
            List<ProductDelayRespVO> delayRecordsByPurchaseId = productDelayService.getRecordsByPurchaseId(currentProduct.getId(), organId);
            if (CollUtil.isNotEmpty(delayRecordsByPurchaseId)) {
                // 产品有效时间展示为延期时间
                return success(LocalDateTimeUtil.format(delayRecordsByPurchaseId.get(0).getDelayTime(), NORM_DATE_FORMATTER));
            }
            // 没有延期记录返回最新的购买记录的结束时间
            expireTime = LocalDateTimeUtil.format(orgPurchaseList.get(0).getEndTime(), NORM_DATE_FORMATTER);
        }
        return success(expireTime);
    }

    @GetMapping("/page")
    @Operation(summary = "查询组织分页")
    @PreAuthorize("@ss.hasAnyPermissions('organizationLIst:query','machine-auth::create','base:plate:query')")
    public CommonResult<PageResult<OrganRespVO>> getOrganPage(@Valid OrganPageReqVO pageVO) {
        PageResult<OrganizationDO> pageResult = organService.getOrganPage(pageVO);
        if(CollUtil.isEmpty(pageResult.getList())) {
            return success(new PageResult<>());
        }
        PageResult<OrganRespVO> bean = BeanUtils.toBean(pageResult, OrganRespVO.class);

        Set<Long> organIds = bean.getList().stream().map(OrganRespVO::getId).collect(Collectors.toSet());
        // 查询当次列表组织下的所有购买记录
        List<PurchaseRecordDO> orgPurchaseList = purchaseService.getOrgPurchaseList(organIds)
                .stream().filter(p -> PurchaseRecordStatusEnum.ACTIVE.getStatus().equals(p.getStatus())).collect(Collectors.toList());
        // 匹配到对应的组织下
        bean.getList().forEach(e -> {
            List<OrganPagePurchaseRespVO> purchaseRespVOList = orgPurchaseList.stream()
                    .filter(f -> Objects.equals(f.getOrganId(), e.getId()))
                    .map(m -> BeanUtils.toBean(m, OrganPagePurchaseRespVO.class))
                    .toList();
            // 查询购买记录下的延期记录
            purchaseRespVOList.forEach(p -> {
                p.setPrice(p.getTotalAmount());
                List<ProductDelayRespVO> delayRecordsByPurchaseId = productDelayService.getRecordsByPurchaseId(p.getId(), e.getId());
                if (CollUtil.isNotEmpty(delayRecordsByPurchaseId)) {
                    // 产品有效时间展示为第一项的计算延期时间
                    p.setEndTime(delayRecordsByPurchaseId.get(0).getDelayTime());
                    // 延期时长展示为延期记录的时长+单位，用顿号分隔
                    p.setDelayDuration(delayRecordsByPurchaseId.stream().map(m -> m.getDelayDuration() + i18nUtils.getMessage(DurationUnitEnum.getDesc(m.getDelayDurationUnit()))).collect(Collectors.joining("、")));
                }
            });
            e.setOrganPurchaseList(purchaseRespVOList);
        });
        return success(bean);
    }

    @GetMapping("/export-excel")
    @Operation(summary = "导出组织 Excel")
    @PreAuthorize("@ss.hasPermission('organizationLIst:export')")
    @OperateLog(type = EXPORT)
    public void exportOrganExcel(@Valid OrganPageReqVO exportReqVO,
                                  HttpServletResponse response) throws IOException {
        exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
        List<OrganizationDO> list = organService.getOrganPage(exportReqVO).getList();
        if(CollUtil.isEmpty(list)) {
            ExcelUtils.write(response, "组织.xls", "数据", OrganExportRespVO.class, new ArrayList<>());
            return;
        }
        Set<Long> organIds = list.stream().map(OrganizationDO::getId).collect(Collectors.toSet());
        List<OrganExportRespVO> organExportRespVOS = BeanUtils.toBean(list, OrganExportRespVO.class);
        List<OrganAdminUserRespDTO> organAdminUserRespDTOS = adminUserService.getOrganAdminByOrganIds(organIds);

        organExportRespVOS.forEach(e->{
            e.setUsernames(organAdminUserRespDTOS.stream()
                    .filter(f->Objects.equals(e.getId(), f.getOrganId()))
                    .map(OrganAdminUserRespDTO::getUsername)
                    .reduce("", (a,b)-> a + " " + b)
            );
        });

        // 导出 Excel
        ExcelUtils.write(response, "组织.xls", "数据", OrganExportRespVO.class, organExportRespVOS);
    }


    @GetMapping({"/list-all-simple", "/simple-list"})
    @Operation(summary = "获取组织精简信息列表", description = "主要用于前端的下拉选项")
    @Parameter(name = "name", description = "组织名称", required = false, example = "xxx")
//    @PreAuthorize("@ss.hasPermission('organizationLIst:query')")
    public CommonResult<List<OrganSimpleRespVO>> getSimpleOrganList(@RequestParam(required = false, value = "name") String name) {
        return success(organService.getSimpleOrganList(name));
    }

    @GetMapping("/account/overview")
    @Operation(summary = "获取组织账户总览")
    public CommonResult<OrganProductOverviewRespVO> getOrganProductOverview() {
        return success(organAmountService.getOrganProductOverview());
    }
}
