/*
 * Copyright ©2023 CJB-CNIT Team. All rights reserved
 */
package com.openhis.web.common.appservice.impl;

import java.util.*;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.core.common.core.domain.R;
import com.core.common.utils.AgeCalculatorUtil;
import com.core.common.utils.SecurityUtils;
import com.core.common.utils.StringUtils;
import com.core.common.utils.bean.BeanUtils;
import com.openhis.administration.domain.Location;
import com.openhis.administration.domain.Organization;
import com.openhis.administration.domain.Supplier;
import com.openhis.administration.domain.TraceNoManage;
import com.openhis.administration.mapper.TraceNoManageMapper;
import com.openhis.administration.service.ILocationService;
import com.openhis.administration.service.IOrganizationService;
import com.openhis.administration.service.IPractitionerRoleService;
import com.openhis.administration.service.ISupplierService;
import com.openhis.common.constant.CommonConstants;
import com.openhis.common.enums.*;
import com.openhis.common.utils.EnumUtils;
import com.openhis.common.utils.HisQueryUtils;
import com.openhis.financial.domain.Contract;
import com.openhis.financial.mapper.ContractMapper;
import com.openhis.web.chargemanage.dto.ContractMetadata;
import com.openhis.web.common.appservice.ICommonService;
import com.openhis.web.common.dto.*;
import com.openhis.web.common.mapper.CommonAppMapper;
import com.openhis.workflow.domain.InventoryItem;
import com.openhis.workflow.service.IInventoryItemService;

/**
 * app常用接口
 *
 * @author zwh
 * @date 2025-04-01
 */
@Service
public class CommonServiceImpl implements ICommonService {

    @Resource
    private TraceNoManageMapper traceNoManageMapper;

    @Resource
    private CommonAppMapper commonAppMapper;

    @Resource
    private ILocationService locationService;

    @Resource
    private IPractitionerRoleService practitionerRoleService;

    @Resource
    private IOrganizationService organizationService;

    @Resource
    private IInventoryItemService inventoryItemService;

    @Resource
    private ContractMapper contractMapper;

    @Resource
    private ISupplierService supplierService;

    /**
     * 获取药房列表
     *
     * @return 药房列表
     */
    @Override
    public List<LocationDto> getPharmacyList() {

        List<Location> pharmacyList = locationService.getPharmacyList();

        List<LocationDto> locationDtoList = new ArrayList<>();
        LocationDto locationDto;
        for (Location location : pharmacyList) {
            locationDto = new LocationDto();
            BeanUtils.copyProperties(location, locationDto);
            locationDtoList.add(locationDto);
        }


        return locationDtoList;
    }

    /**
     * 获取药房列表(库房用)
     *
     * @return 药房列表
     */
    @Override
    public List<LocationDto> getInventoryPharmacyList() {

        // 用户id
        Long practitionerId = SecurityUtils.getLoginUser().getPractitionerId();
        // 根据用户id获得管理库房信息
        List<Long> locationIds = practitionerRoleService.getLocationIdsByPractitionerId(practitionerId);

        List<Location> pharmacyList = locationService.getPharmacyList();
        List<LocationDto> locationDtoList = new ArrayList<>();
        LocationDto locationDto;
        for (Location location : pharmacyList) {
            for (Long locationId : locationIds) {
                if (location.getId().equals(locationId)) {
                    locationDto = new LocationDto();
                    BeanUtils.copyProperties(location, locationDto);
                    locationDtoList.add(locationDto);
                }
            }
        }
        return locationDtoList;
    }

    /**
     * 获取药库列表
     *
     * @return 药库列表
     */
    @Override
    public List<LocationDto> getCabinetList() {
        List<Location> pharmacyList = locationService.getCabinetList();
        List<LocationDto> locationDtoList = new ArrayList<>();
        LocationDto locationDto;
        for (Location location : pharmacyList) {
            locationDto = new LocationDto();
            BeanUtils.copyProperties(location, locationDto);
            locationDtoList.add(locationDto);
        }
        return locationDtoList;
    }

    /**
     * 获取仓库列表
     *
     * @return 仓库列表
     */
    @Override
    public List<LocationDto> getWarehouseList() {
        List<Location> pharmacyList = locationService.getWarehouseList();
        List<LocationDto> locationDtoList = new ArrayList<>();
        LocationDto locationDto;
        for (Location location : pharmacyList) {
            locationDto = new LocationDto();
            BeanUtils.copyProperties(location, locationDto);
            locationDtoList.add(locationDto);
        }
        return locationDtoList;
    }

    /**
     * 获取药库列表(库房用)
     *
     * @return 药库列表
     */
    @Override
    public List<LocationDto> getInventoryCabinetList() {
        // 用户id
        Long practitionerId = SecurityUtils.getLoginUser().getPractitionerId();
        // 根据用户id获得管理库房信息
        List<Long> locationIds = practitionerRoleService.getLocationIdsByPractitionerId(practitionerId);

        List<Location> pharmacyList = locationService.getCabinetList();
        List<LocationDto> locationDtoList = new ArrayList<>();
        LocationDto locationDto;
        for (Location location : pharmacyList) {
            for (Long locationId : locationIds) {
                if (location.getId().equals(locationId)) {
                    locationDto = new LocationDto();
                    BeanUtils.copyProperties(location, locationDto);
                    locationDtoList.add(locationDto);
                }
            }
        }
        return locationDtoList;
    }

    /**
     * 药房药库列表
     *
     * @return 药房药库列表
     */
    @Override
    public List<LocationDto> getPharmacyCabinetList() {
        List<Location> pharmacyCabinetList = locationService.getPharmacyCabinetList();
        List<LocationDto> locationDtoList = new ArrayList<>();
        LocationDto locationDto;
        for (Location location : pharmacyCabinetList) {
            locationDto = new LocationDto();
            BeanUtils.copyProperties(location, locationDto);
            locationDtoList.add(locationDto);
        }
        return locationDtoList;
    }

    /**
     * 获取病区列表
     *
     * @param orgId 科室id
     * @return 病区列表
     */
    @Override
    public List<LocationDto> getWardList(Long orgId) {
        List<Location> getWardList = new ArrayList<>();
        if (orgId != null) {
            getWardList = locationService.getWardList(orgId);
        } else {
            getWardList = locationService.getWardList(null);
        }
        List<LocationDto> locationDtoList = new ArrayList<>();
        LocationDto locationDto;
        for (Location location : getWardList) {
            locationDto = new LocationDto();
            BeanUtils.copyProperties(location, locationDto);
            locationDtoList.add(locationDto);
        }
        return locationDtoList;
    }

    /**
     * 库存项目下拉列表（药库业务使用）
     *
     * @param inventoryItemParam 查询条件
     * @param searchKey 模糊查询关键字
     * @param pageNo 当前页
     * @param pageSize 每页多少条
     * @return 库存项目信息
     */
    @Override
    public R<?> getInventoryItemList(InventoryItemParam inventoryItemParam, String searchKey, Integer pageNo,
        Integer pageSize) {
        Integer purchaseFlag = inventoryItemParam.getPurchaseFlag();
        inventoryItemParam.setPurchaseFlag(null);

        // 构建查询条件
        QueryWrapper<InventoryItemParam> queryWrapper = HisQueryUtils.buildQueryWrapper(inventoryItemParam, searchKey,
            new HashSet<>(Arrays.asList(CommonConstants.FieldName.Name, CommonConstants.FieldName.PyStr,
                CommonConstants.FieldName.WbStr)),
            null);
        // 查询库存项目信息
        IPage<InventoryItemDto> inventoryItems = commonAppMapper.selectInventoryItemList(new Page<>(pageNo, pageSize),
            CommonConstants.TableName.MED_MEDICATION_DEFINITION, CommonConstants.TableName.ADM_DEVICE_DEFINITION,
            ItemType.MEDICINE.getValue(), ItemType.DEVICE.getValue(), purchaseFlag, ConditionCode.PURCHASE.getCode(),
            PublicationStatus.RETIRED.getValue(), queryWrapper);
        List<InventoryItemDto> inventoryItemDtoList = inventoryItems.getRecords();
        inventoryItemDtoList.forEach(e -> {
            // 项目类型
            e.setItemType_enumText(EnumUtils.getInfoByValue(ItemType.class, e.getItemType()));
        });
        for (InventoryItemDto inventoryItem : inventoryItemDtoList) {
            List<UnitDto> unitList = new ArrayList<>();
            UnitDto unitDto = new UnitDto();
            // 单位列表
            unitDto.setUnitCode(inventoryItem.getUnitCode()).setMinUnitCode(inventoryItem.getMinUnitCode());
            unitList.add(unitDto);
            inventoryItem.setUnitList(unitList);
        }
        return R.ok(inventoryItemDtoList);
    }

    /**
     * 根据项目相关信息查询项目库存相关信息
     *
     * @param inventoryItemParam 项目id
     * @return 项目库存相关信息
     */
    @Override
    public R<?> getInventoryItemInfo(InventoryItemParam inventoryItemParam) {
        // 查询项目库存相关信息
        List<LocationInventoryDto> locationInventoryDtoList = commonAppMapper.selectInventoryItemInfo(
            inventoryItemParam.getOrgLocationId(), CommonConstants.TableName.MED_MEDICATION_DEFINITION,
            CommonConstants.TableName.ADM_DEVICE_DEFINITION, inventoryItemParam.getObjLocationId(),
            inventoryItemParam.getLotNumber(), inventoryItemParam.getItemId(), ConditionCode.PURCHASE.getCode());

        // 医保编码和生产厂家校验
        for (LocationInventoryDto dto : locationInventoryDtoList) {
            if (StringUtils.isNotEmpty(dto.getYbNo()) && StringUtils.isEmpty(dto.getManufacturerText())) {
                return R.fail("生产厂家不能为空，请到药品目录维护");
            }
        }
        return R.ok(locationInventoryDtoList);
    }

    /**
     * 科室列表
     *
     * @return 科室列表
     */
    @Override
    public R<?> getDepartmentList() {
        return R.ok(organizationService.getList(OrganizationType.DEPARTMENT.getValue(), null));
    }

    /**
     * 科室列表
     *
     * @return 科室列表
     */
    @Override
    public List<Organization> departmentList() {
        return organizationService.getList(OrganizationType.DEPARTMENT.getValue(), null);
    }

    /**
     * 根据追溯码获取药品/耗材信息
     *
     * @param traceNoList 追溯码列表
     * @return 项目信息
     */
    @Override
    public R<?> getItemInfoByTraceNo(List<String> traceNoList) {
        Map<String, String> traceNoMap = new HashMap<>();
        for (String traceNo : traceNoList) {
            if (traceNo != null && !StringUtils.isEmpty(traceNo)) {
                // 数据源更改
                InventoryItem inventoryItem = inventoryItemService.getOne(
                    new LambdaQueryWrapper<InventoryItem>().like(InventoryItem::getTraceNo, traceNo).last("LIMIT 1"));
                if (inventoryItem != null) {
                    String itemId = inventoryItem.getItemId().toString();
                    // TraceNoManage traceNoManage = commonAppMapper.getInfoByTraceNo("%" + traceNo + "%");
                    // if (traceNoManage != null) {
                    // String itemId = traceNoManage.getItemId().toString();
                    // 如果map中已经存在该itemId，拼接traceNo，否则直接添加
                    if (traceNoMap.containsKey(itemId)) {
                        String existingTraceNos = traceNoMap.get(itemId);
                        traceNoMap.put(itemId, existingTraceNos + CommonConstants.Common.COMMA + traceNo);
                    } else {
                        traceNoMap.put(itemId, traceNo);
                    }
                } else {
                    return R.ok(null);
                }
            }
        }
        return R.ok(traceNoMap);
    }

    /**
     * 追溯码查询
     *
     * @param searchTraceNoParam 查询条件
     * @return 项目信息
     */
    @Override
    public R<?> searchTraceNo(SearchTraceNoParam searchTraceNoParam) {
        List<TraceNoManage> traceNoManageList = new ArrayList<>();
        Map<String, String> traceNoMap = new HashMap<>();
        // 判断传入的是药品还是耗材，查询追溯码状态只有进的数据
        if (searchTraceNoParam.getItemType().equals(ItemType.MEDICINE.getValue())) {
            traceNoManageList = traceNoManageMapper.getItemTraceNoInfo(
                CommonConstants.TableName.MED_MEDICATION_DEFINITION, searchTraceNoParam.getItemId(),
                searchTraceNoParam.getLocationId(), searchTraceNoParam.getLotNumber());
        } else if (searchTraceNoParam.getItemType().equals(ItemType.DEVICE.getValue())) {
            traceNoManageList = traceNoManageMapper.getItemTraceNoInfo(CommonConstants.TableName.ADM_DEVICE_DEFINITION,
                searchTraceNoParam.getItemId(), searchTraceNoParam.getLocationId(), searchTraceNoParam.getLotNumber());
        }
        if (traceNoManageList != null) {
            for (TraceNoManage traceNoItem : traceNoManageList) {
                traceNoMap.put(traceNoItem.getItemId().toString(), traceNoItem.getTraceNo());
            }
        }
        return R.ok(traceNoMap);
    }

    /**
     * 查询费用性质
     *
     * @return 费用性质
     */
    @Override
    public R<?> getContractMetadata() {
        // TODO: Contract表的基础数据维护还没做,具体不知道状态字段的取值是什么,先查询默认值为0的数据
        List<Contract> ContractList =
            contractMapper.selectList(new LambdaQueryWrapper<Contract>().eq(Contract::getStatusEnum, 0));
        // 复制同名字段并 return
        return R.ok(ContractList.stream().map(contract -> {
            ContractMetadata metadata = new ContractMetadata();
            try {
                BeanUtils.copyProperties(contract, metadata);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return metadata;
        }).collect(Collectors.toList()));
    }

    /**
     * 根据科室查询护士
     *
     * @param orgId 科室id
     * @return 护士列表
     */
    @Override
    public R<?> getNurseListByOrg(Long orgId) {
        return R.ok(practitionerRoleService.getNurseList(orgId));
    }

    /**
     * 根据父级位置id查询他所有的子集
     *
     * @param locationId 位置id
     * @param locationForm 位置类型
     * @return 位置列表
     */
    @Override
    public List<LocationDto> getChildLocation(Long locationId, Integer locationForm) {
        // 获取当前位置信息
        Location location = locationService.getById(locationId);
        // 查询所有子集位置
        List<Location> childLocations = locationService.list(new LambdaQueryWrapper<Location>()
            .likeRight(Location::getBusNo, location.getBusNo()).eq(Location::getFormEnum, locationForm)
            .ne(Location::getStatusEnum, LocationStatus.INACTIVE.getValue()));
        List<LocationDto> locationDtoList = new ArrayList<>();
        LocationDto locationDto;
        for (Location childLocation : childLocations) {
            locationDto = new LocationDto();
            BeanUtils.copyProperties(childLocation, locationDto);
            locationDtoList.add(locationDto);
        }
        // 8. 返回成功响应
        return locationDtoList;
    }

    /**
     * 查询登录者管理的病区
     *
     * @return 病区列表
     */
    @Override
    public List<LocationDto> getPractitionerWard() {
        // 查询当前登录者管理的病区
        Long practitionerId = SecurityUtils.getLoginUser().getPractitionerId();
        List<Long> locationIds = practitionerRoleService.getLocationIdsByPractitionerId(practitionerId);
        List<Location> locationList = locationService.getLocationList(locationIds);
        List<Location> wardList = new ArrayList<>();
        for (Location ward : locationList) {
            if (LocationForm.WARD.getValue().equals(ward.getFormEnum())) {
                wardList.add(ward);
            }
        }
        List<LocationDto> locationDtoList = new ArrayList<>();
        LocationDto locationDto;
        for (Location ward : wardList) {
            locationDto = new LocationDto();
            BeanUtils.copyProperties(ward, locationDto);
            locationDtoList.add(locationDto);
        }
        return locationDtoList;
    }

    /**
     * 查询参与者下拉列表
     *
     * @param searchKey 模糊查询关键字
     * @return 参与者下拉列表
     */
    @Override
    public R<?> getPractitionerList(String searchKey) {
        return R.ok(commonAppMapper.getPractitionerList(searchKey));
    }

    /**
     * 查询医嘱打印信息
     *
     * @param requestIds 请求ids
     * @param isPrescription 是否为处方
     * @return 医嘱打印单
     */
    @Override
    public R<?> getAdvicePrintInfo(List<Long> requestIds, String isPrescription) {
        AdvicePrintInfoDto advicePrintInfoDto;
        if (Whether.YES.getCode().equals(isPrescription)) {
            // 查询处方单
            advicePrintInfoDto = commonAppMapper.selectPrescriptionPrintInfo(requestIds);
        } else {
            // 查询处置单
            advicePrintInfoDto = commonAppMapper.selectTreatmentPrintInfo(requestIds);
        }
        advicePrintInfoDto
            .setAge(advicePrintInfoDto.getBirthDate() != null
                ? AgeCalculatorUtil.getAge(advicePrintInfoDto.getBirthDate()) : "")
            .setGenderEnum_enumText(
                EnumUtils.getInfoByValue(AdministrativeGender.class, advicePrintInfoDto.getGenderEnum()))
            .setEncounterYbClass_enumText(
                EnumUtils.getInfoByValue(EncounterYbClass.class, advicePrintInfoDto.getEncounterYbClass()));
        return R.ok(advicePrintInfoDto);
    }

    /**
     * 查询参与者签名
     *
     * @param practitionerId 参与者id
     * @return 参与者签名
     */
    @Override
    public R<?> getPractitionerSignature(Long practitionerId) {
        return R.ok(commonAppMapper.getPractitionerSignature(practitionerId));
    }

    /**
     * 查询所有供应商
     *
     * @return 供应商
     */
    @Override
    public R<?> getSupplierList() {
        return R.ok(supplierService.list(new LambdaQueryWrapper<Supplier>().select(Supplier::getId, Supplier::getName)
            .eq(Supplier::getTypeEnum, SupplierType.SUPPLIER.getValue())
            .eq(Supplier::getDeleteFlag, DelFlag.NO.getCode()).eq(Supplier::getActiveFlag, Whether.YES.getValue())));
    }

    /**
     * 查询所有诊疗项目
     *
     * @return 诊疗项目
     */
    @Override
    public R<?> getActivityDefinition() {
        return R.ok(commonAppMapper.getActivityDefinition(PublicationStatus.ACTIVE.getValue()));
    }

}
