package com.xiaoniu.subsystem.business.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.xiaoniu.common.core.result.R;
import com.xiaoniu.common.core.utils.BeanUtil;
import com.xiaoniu.common.core.utils.StringUtils;
import com.xiaoniu.common.core.vo.AnalysisLineVO;
import com.xiaoniu.common.core.vo.LabelAndValueNameVO;
import com.xiaoniu.common.core.vo.LabelAndValueVO;
import com.xiaoniu.common.log.annotation.Log;
import com.xiaoniu.common.log.enums.BusinessType;
import com.xiaoniu.subsystem.business.domain.Expense;
import com.xiaoniu.subsystem.business.domain.dto.ExpenseStatisticsDTO;
import com.xiaoniu.subsystem.business.domain.vo.*;
import com.xiaoniu.subsystem.business.service.IExpenseService;
import com.xiaoniu.subsystem.business.service.IStatisticalAnalysisService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.math.BigDecimal;
import java.util.List;
import java.util.Objects;

/**
 * @Author haoxuyang
 * @Date 2024/11/29 14:23
 */
@RestController
@AllArgsConstructor
@RequestMapping("/statistics")
@Tag(name = "统计分析", description = "统计分析接口")
public class StatisticalAnalysisController {

    private final IExpenseService expenseService;

    private final IStatisticalAnalysisService statisticalAnalysisService;

    @GetMapping("/excellentStudent")
    @ApiOperationSupport(order = 1)
    @Operation(summary = "培训人员-历年优秀学员统计")
    public R<AnalysisLineVO> excellentStudent() {
        return R.data(statisticalAnalysisService.excellentStudent());
    }

    @GetMapping("/numberParticipants")
    @ApiOperationSupport(order = 2)
    @Operation(summary = "培训人员-计划、实际参训人数统计")
    public R<NumberParticipantsVO> numberParticipants() {
        return R.data(statisticalAnalysisService.numberParticipants());
    }

    @GetMapping("/overYearsParticipants")
    @ApiOperationSupport(order = 3)
    @Operation(summary = "培训人员-历年参训人员统计")
    public R<AnalysisLineVO> overYearsParticipants() {
        return R.data(statisticalAnalysisService.overYearsParticipants());
    }

    @GetMapping("/trainingType")
    @ApiOperationSupport(order = 4)
    @Operation(summary = "培训人员-参训人员培训类型占比图")
    public R<List<LabelAndValueVO>> trainingType() {
        return R.data(statisticalAnalysisService.trainingType());
    }

    @GetMapping("/comparisonGrades")
    @ApiOperationSupport(order = 5)
    @Operation(summary = "培训人员-参训人员入学摸底考试与结业考核成绩对比图")
    public R<AnalysisLineVO> comparisonGrades() {
        return R.data(statisticalAnalysisService.comparisonGrades());
    }

    @GetMapping("/scoreProportion")
    @ApiOperationSupport(order = 6)
    @Operation(summary = "培训人员-参训人员成绩占比图")
    public R<List<LabelAndValueVO>> scoreProportion() {
        return R.data(statisticalAnalysisService.scoreProportion());
    }

    /**
     * 费用统计总体-人员统计
     */
    @GetMapping("/expense/personnel")
    @ApiOperationSupport(order = 7)
    @Log(title = "费用统计总体-人员统计", businessType = BusinessType.OTHER)
    @Operation(summary = "费用统计总体-人员统计", description = "传入dto")
    public R<List<LabelAndValueNameVO>> expensePersonnel(ExpenseStatisticsDTO dto) {
        return R.data(statisticalAnalysisService.expensePersonnel(dto));
    }

    /**
     * 费用统计总体-培训费
     */
    @GetMapping("/expense/amount")
    @ApiOperationSupport(order = 8)
    @Log(title = "费用统计总体-培训费", businessType = BusinessType.OTHER)
    @Operation(summary = "费用统计总体-培训费", description = "传入dto")
    public R<AnalysisLineVO> expenseAmount(ExpenseStatisticsDTO dto) {
        return R.data(statisticalAnalysisService.expenseAmount(dto));
    }

    /**
     * 费用统计总体-费用类型
     */
    @GetMapping("/expense/type")
    @ApiOperationSupport(order = 9)
    @Log(title = "费用统计总体-费用类型", businessType = BusinessType.OTHER)
    @Operation(summary = "费用统计总体-费用类型", description = "传入dto")
    public R<TypeStatisticsVO> expenseType(ExpenseStatisticsDTO dto) {
        return R.data(statisticalAnalysisService.expenseType(dto));
    }

    /**
     * 费用统计总体-承训单位费用占比
     */
    @GetMapping("/expense/unit")
    @ApiOperationSupport(order = 10)
    @Log(title = "费用统计总体-承训单位费用占比", businessType = BusinessType.OTHER)
    @Operation(summary = "费用统计总体-承训单位费用占比", description = "传入dto")
    public R<TypeStatisticsVO> expenseUnit(ExpenseStatisticsDTO dto) {
        return R.data(statisticalAnalysisService.expenseUnit(dto));
    }

    /**
     * 费用统计总体-战区费用占比
     */
    @GetMapping("/expense/operations")
    @ApiOperationSupport(order = 11)
    @Log(title = "费用统计总体-战区费用占比", businessType = BusinessType.OTHER)
    @Operation(summary = "费用统计总体-战区费用占比", description = "传入dto")
    public R<TypeStatisticsVO> expenseOperations(ExpenseStatisticsDTO dto) {
        return R.data(statisticalAnalysisService.expenseOperations(dto));
    }

    /**
     * 费用统计-人均费用统计
     */
    @GetMapping("/expense/per/capita")
    @ApiOperationSupport(order = 12)
    @Log(title = "费用统计-人均费用统计", businessType = BusinessType.OTHER)
    @Operation(summary = "费用统计-人均费用统计", description = "传入dto")
    public R<AnalysisLineVO> expensePerCapita(ExpenseStatisticsDTO dto) {
        return R.data(statisticalAnalysisService.expensePerCapita(dto));
    }

    /**
     * 费用统计总体-结算单
     */
    @GetMapping("/expense/final/statement")
    @ApiOperationSupport(order = 13)
    @Log(title = "费用统计总体-结算单", businessType = BusinessType.OTHER)
    @Operation(summary = "费用统计总体-结算单", description = "传入dto")
    public R<ExpenseDetailVO> expenseFinalStatement(ExpenseStatisticsDTO dto) {
        Expense expense = expenseService.getOne(new LambdaQueryWrapper<Expense>()
                .eq(Expense::getFlightId, dto.getFlightId()));
        if (null == expense) {
            return R.data(new ExpenseDetailVO());
        }
        return R.data(set(expense));
    }

    /**
     * 费用统计总体-费用明细
     */
    @GetMapping("/expense/detail")
    @ApiOperationSupport(order = 14)
    @Log(title = "费用统计总体-费用明细", businessType = BusinessType.OTHER)
    @Operation(summary = "费用统计总体-费用明细", description = "传入dto")
    public R<ExpenseDetailVO> expenseDetail(ExpenseStatisticsDTO dto) {
        Expense expense = expenseService.getOne(new LambdaQueryWrapper<Expense>()
                .eq(Expense::getFlightId, dto.getFlightId()));
        if (null == expense) {
            return R.data(new ExpenseDetailVO());
        }
        return R.data(set(expense));
    }

    @GetMapping("/flightNumberParticipants")
    @ApiOperationSupport(order = 13)
    @Operation(summary = "班次统计-计划、实际参训人数统计")
    public R<NumberParticipantsVO> flightNumberParticipants(ExpenseStatisticsDTO dto) {
        return R.data(statisticalAnalysisService.flightNumberParticipants(dto));
    }

    @GetMapping("/flightTrainingCourseNum")
    @ApiOperationSupport(order = 14)
    @Operation(summary = "班次统计-培训班数量")
    public R<AnalysisLineVO> flightTrainingCourseNum(ExpenseStatisticsDTO dto) {
        return R.data(statisticalAnalysisService.flightTrainingCourseNum(dto));
    }

    @GetMapping("/flightTrainingStatus")
    @ApiOperationSupport(order = 15)
    @Operation(summary = "班次统计-培训状态")
    public R<FlightTrainingStatusVO> flightTrainingStatus(ExpenseStatisticsDTO dto) {
        return R.data(statisticalAnalysisService.flightTrainingStatus(dto));
    }

    @GetMapping("/flightNumProportion")
    @ApiOperationSupport(order = 16)
    @Operation(summary = "班次统计-各承训开设班次数量占比")
    public R<List<LabelAndValueVO>> flightNumProportion(ExpenseStatisticsDTO dto) {
        return R.data(statisticalAnalysisService.flightNumProportion(dto));
    }

    @GetMapping("/flightTrainingType")
    @ApiOperationSupport(order = 17)
    @Operation(summary = "班次统计-培训类型")
    public R<List<LabelAndValueVO>> flightTrainingType(ExpenseStatisticsDTO dto) {
        return R.data(statisticalAnalysisService.flightTrainingType(dto));
    }

    @GetMapping("/flightDistributionTrainees")
    @ApiOperationSupport(order = 18)
    @Operation(summary = "班次统计-参训人员分布")
    public R<AnalysisLineVO> flightDistributionTrainees(ExpenseStatisticsDTO dto) {
        return R.data(statisticalAnalysisService.flightDistributionTrainees(dto));
    }

    @GetMapping("/flightDistributionProportion")
    @ApiOperationSupport(order = 19)
    @Operation(summary = "班次统计-参训人员占比")
    public R<FlightDistributionProportionVO> flightDistributionProportion(ExpenseStatisticsDTO dto) {
        return R.data(statisticalAnalysisService.flightDistributionProportion(dto));
    }

    @GetMapping("/flightAnnualExcellenceRate")
    @ApiOperationSupport(order = 20)
    @Operation(summary = "班次统计-历年优秀率")
    public R<AnalysisLineVO> flightAnnualExcellenceRate(ExpenseStatisticsDTO dto) {
        return R.data(statisticalAnalysisService.flightAnnualExcellenceRate(dto));
    }

    @GetMapping("/flightProportionGrades")
    @ApiOperationSupport(order = 20)
    @Operation(summary = "班次统计-成绩占比图")
    public R<List<LabelAndValueVO>> flightProportionGrades(ExpenseStatisticsDTO dto) {
        return R.data(statisticalAnalysisService.flightProportionGrades(dto));
    }

    @GetMapping("/flightExpenseSettlement")
    @ApiOperationSupport(order = 21)
    @Operation(summary = "班次统计-费用结算信息统计")
    public R<AnalysisLineVO> flightExpenseSettlement(ExpenseStatisticsDTO dto) {
        return R.data(statisticalAnalysisService.flightExpenseSettlement(dto));
    }



    private ExpenseDetailVO set(Expense expense){
        ExpenseDetailVO vo = Objects.requireNonNull(BeanUtil.copy(expense, ExpenseDetailVO.class))
                .setRoomsNumber(verify(expense.getRoomsNumber()) ?
                        Integer.parseInt(expense.getRoomsNumber()) : 0)
                .setRoomsUnitPrice(verify(expense.getRoomsUnitPrice()) ?
                        BigDecimal.valueOf(Double.parseDouble(expense.getRoomsUnitPrice())) : BigDecimal.ZERO)
                .setAccommodationCost(verify(expense.getAccommodationCost()) ?
                        BigDecimal.valueOf(Double.parseDouble(expense.getAccommodationCost())) : BigDecimal.ZERO)
                .setMealsUnitPrice(verify(expense.getMealsUnitPrice()) ?
                        BigDecimal.valueOf(Double.parseDouble(expense.getMealsUnitPrice())) : BigDecimal.ZERO)
                .setBoardMoney(verify(expense.getBoardMoney()) ?
                        BigDecimal.valueOf(Double.parseDouble(expense.getBoardMoney())) : BigDecimal.ZERO)
                .setConferenceRoomNumber(verify(expense.getConferenceRoomNumber()) ?
                        Integer.parseInt(expense.getConferenceRoomNumber()) : 0)
                .setConferenceRoomUnitPrice(verify(expense.getConferenceRoomUnitPrice()) ?
                        BigDecimal.valueOf(Double.parseDouble(expense.getConferenceRoomUnitPrice())) : BigDecimal.ZERO)
                .setConferenceRoom(verify(expense.getConferenceRoom()) ?
                        BigDecimal.valueOf(Double.parseDouble(expense.getConferenceRoom())) : BigDecimal.ZERO)
                .setWorkshopNumber(verify(expense.getWorkshopNumber()) ?
                        Integer.parseInt(expense.getWorkshopNumber()) : 0)
                .setWorkshopUnitPrice(verify(expense.getWorkshopUnitPrice()) ?
                        BigDecimal.valueOf(Double.parseDouble(expense.getWorkshopUnitPrice())) : BigDecimal.ZERO)
                .setProductionWorkshop(verify(expense.getProductionWorkshop()) ?
                        BigDecimal.valueOf(Double.parseDouble(expense.getProductionWorkshop())) : BigDecimal.ZERO)
                .setTrainingMaterialsFee(verify(expense.getTrainingMaterialsFee()) ?
                        BigDecimal.valueOf(Double.parseDouble(expense.getTrainingMaterialsFee())) : BigDecimal.ZERO)
                .setTransportatioExpense(verify(expense.getTransportatioExpense()) ?
                        BigDecimal.valueOf(Double.parseDouble(expense.getTransportatioExpense())) : BigDecimal.ZERO)
                .setLectureFee(verify(expense.getLectureFee()) ?
                        BigDecimal.valueOf(Double.parseDouble(expense.getLectureFee())) : BigDecimal.ZERO)
                .setQuotaStandard(verify(expense.getQuotaStandard()) ?
                        BigDecimal.valueOf(Double.parseDouble(expense.getQuotaStandard())) : BigDecimal.ZERO)
                .setOrganBudgetedAmount(verify(expense.getOrganBudgetedAmount()) ?
                        BigDecimal.valueOf(Double.parseDouble(expense.getOrganBudgetedAmount())) : BigDecimal.ZERO)
                .setTrainingBudgetedAmount(verify(expense.getTrainingBudgetedAmount()) ?
                        BigDecimal.valueOf(Double.parseDouble(expense.getTrainingBudgetedAmount())) : BigDecimal.ZERO)
                .setSettlementAmount(verify(expense.getSettlementAmount()) ?
                        BigDecimal.valueOf(Double.parseDouble(expense.getSettlementAmount())) : BigDecimal.ZERO)
                .setSupportManagementFee(verify(expense.getSupportManagementFee()) ?
                        BigDecimal.valueOf(Double.parseDouble(expense.getSupportManagementFee())) : BigDecimal.ZERO)
                .setPlannedNumber(verify(expense.getPlannedNumber()) ?
                        Integer.parseInt(expense.getPlannedNumber()) : 0)
                .setParticipantsNumber(verify(expense.getParticipantsNumber()) ?
                        Integer.parseInt(expense.getParticipantsNumber()) : 0)
                .setTrainingDays(verify(expense.getTrainingDays()) ?
                        BigDecimal.valueOf(Double.parseDouble(expense.getTrainingDays())) : BigDecimal.ZERO);
        vo.setTotal(BigDecimal.ZERO
                .add(null != vo.getAccommodationCost() ? vo.getAccommodationCost() : BigDecimal.ZERO)
                .add(null != vo.getBoardMoney() ? vo.getBoardMoney() : BigDecimal.ZERO)
                .add(null != vo.getConferenceRoom() ? vo.getConferenceRoom() : BigDecimal.ZERO)
                .add(null != vo.getProductionWorkshop() ? vo.getProductionWorkshop() : BigDecimal.ZERO)
                .add(null != vo.getTrainingMaterialsFee() ? vo.getTrainingMaterialsFee() : BigDecimal.ZERO)
                .add(null != vo.getTransportatioExpense() ? vo.getTransportatioExpense() : BigDecimal.ZERO)
                .add(null != vo.getLectureFee() ? vo.getLectureFee() : BigDecimal.ZERO)
                .add(null != vo.getSupportManagementFee() ? vo.getSupportManagementFee() : BigDecimal.ZERO));
        return vo;
    }

    private Boolean verify(String str){
        if(StringUtils.isBlank(str) || str.equals("null")) return false;
        return true;
    }
}
