import { CardStepTitle, StatusIcon, UploadWrongLocalHeaderError } from "@/components";
import ExamGradeController from "@/services/apis/ExamGradeController";
import ExamPlanController from "@/services/apis/ExamPlanController";
import ExamStudentController from "@/services/apis/ExamStudentController";
import SysOrgController from "@/services/apis/SysOrgController";
import { CertificateType, DataImportMode, EducationStage, Gender } from "@/services/enums";
import { BulbOutlined, InboxOutlined } from "@ant-design/icons";
import { ActionType, PageContainer, ProCard, ProColumns, ProForm, ProFormInstance, ProFormSelect, ProTable } from "@ant-design/pro-components";
import { useModel, useParams } from "@umijs/max";
import { useRequest } from "ahooks";
import { Alert, App, Button, Space, Table, Tooltip, Tour, Typography, Upload, theme } from "antd";
import type { RcFile, UploadFile, UploadProps } from "antd/lib/upload/interface";
import lodash from 'lodash';
import { useRef, useState } from "react";
import ExamStudentImportEditModal from "./components/ExamStudentImportEditModal";

type ClassTotalItem = {
    classNumber: number;
    total: number;
    success: number;
    error: number;
};

type ImportFormData = {
    examGradeId: number;
    sysOrgBranchId?: number;
};

/** 监测学生批量导入 */
const OrgExamStudentImport: React.FC = () => {
    const reqParams = useParams() as unknown as { examPlanId: number };

    const formRef = useRef<ProFormInstance<ImportFormData>>();
    const actionRef = useRef<ActionType>();

    const [tourOpen, setTourOpen] = useState(false);
    const currentRef = useRef<API.UploadExamStudentOutput>();
    const [editOpen, setEditOpen] = useState(false);

    const [grade, setGrade] = useState<API.ExamGradeOutput>();

    const { token } = theme.useToken();
    const { message, modal } = App.useApp();

    const { getDictValueEnum } = useModel('useDict');
    const { initialState } = useModel('@@initialState');
    const { currentUser } = initialState ?? {};

    const [fileList, setFileList] = useState<UploadFile[]>([]);
    const [uploading, setUploading] = useState(false);
    const [data, setData] = useState<API.UploadExamDataOutput_UploadExamStudentOutput>();
    const [classTotal, setClassTotal] = useState<ClassTotalItem[]>();
    // const [dataImportMode, setDataImportMode] = useState(DataImportMode.CLEAR_APPEND);

    const tourGradeRef = useRef(null);
    const tourDownloadRef = useRef(null);
    const tourChooseFileRef = useRef(null);
    const tourUploadRef = useRef(null);
    const tourStuCountRef = useRef(null);
    const tourStuDetailRef = useRef(null);
    const tourSubmitRef = useRef(null);

    const { data: baseData, loading } = useRequest(async () => {
        const res1 = await ExamGradeController.getListByExamPlanId({ examplanid: reqParams.examPlanId });
        const res2 = await SysOrgController.getOrgBranchByOrgId({ orgid: currentUser?.sysOrgId ?? 0 });
        const res3 = await ExamPlanController.getById({ id: reqParams.examPlanId });
        return {
            examGrades: res1 ?? [],
            branches: res2 ?? [],
            hasNceeCourseComb: res3?.educationStage === EducationStage.SENIOR_HIGH_SCHOOL_STAGE,
        };
    });

    const uploadProps: UploadProps = {
        onRemove: () => {
            setFileList([]);
        },
        beforeUpload: (file) => {
            setFileList([file]);

            return false;
        },
        fileList,
        multiple: false,
        accept: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel',
    };

    const handleBack = () => history.back();

    // 计算统计数据
    const handleClassTotal = (rows: API.UploadExamStudentOutput[]) => {
        let cts: ClassTotalItem[] = [];
        lodash.forEach(lodash.countBy(rows, 'classNumber'), function (v, k) {
            const classNumber = parseInt(k);
            const success = rows.filter(t => t.classNumber === classNumber && t.isSuccess === true)?.length ?? 0;
            cts.push({
                classNumber,
                total: v,
                success,
                error: v - success,
            });
        });
        setClassTotal(cts);
    }

    // 上传
    const handleUpload = async () => {
        if (!grade) {
            message.error('请先选择年级');
            return;
        }

        const formData = new FormData();
        formData.append('examPlanId', `${reqParams.examPlanId}`);
        formData.append('examGradeId', `${grade?.id}`);
        fileList.forEach((file) => {
            formData.append('file', file as RcFile);
        });
        setUploading(true);
        try {
            const res = await ExamStudentController.upload(formData);
            setData(res);
            handleClassTotal(res?.rows ?? []);
        }
        catch { }
        finally {
            setUploading(false);
        }
    }

    // 保存编辑
    const handleEdit = (v: API.UploadExamStudentOutput) => {
        const i = data?.rows?.findIndex(t => t.rowNumber === v.rowNumber) ?? -1;
        if (i !== -1) {
            const d = { ...data };
            if (d.rows) {
                d.rows[i] = v;
                handleClassTotal(d.rows ?? []);
                setData(d);
            }
        }
    }

    // 删除行
    const handleDelete = (rowNumber: number) => {
        modal.confirm({
            title: '警告',
            content: '确定立即删除吗',
            okText: '确定',
            cancelText: '取消',
            centered: true,
            onOk: async () => {
                const i = data?.rows?.findIndex(t => t.rowNumber === rowNumber) ?? -1;
                if (i !== -1) {
                    const d = { ...data };
                    if (d.rows) {
                        d.rows.splice(i, 1);
                        setData(d);
                        handleClassTotal(d.rows ?? []);
                        message.success('已删除');
                        return;
                    }
                }
                message.error('删除失败');
            },
        });
    }

    // 确认导入
    const handleImport = async () => {
        const sysOrgId = currentUser?.sysOrgId;
        if (!sysOrgId) {
            message.error('获取机构ID错误');
            return;
        }
        try {
            const importFormValues = await formRef.current?.validateFields();
            if (!importFormValues) {
                return;
            }
            const { examGradeId, ...restValues } = importFormValues;
            const grade = baseData?.examGrades.find(t => t.id === examGradeId);
            if (!grade) {
                return;
            }
            const items = [...(data?.rows ?? [])];
            if (items.some(t => t.isSuccess === false)) {
                message.error('还有校验未通过的数据不能导入');
                return;
            }
            modal.confirm({
                title: '导入提示',
                content: '批量导入会覆盖当前选择年级的所有学生信息，确认立即导入吗？',
                okText: '确定',
                cancelText: '取消',
                centered: true,
                onOk: async () => {
                    try {
                        await ExamStudentController.importAction({
                            examPlanId: reqParams.examPlanId,
                            examGradeId,
                            gradeId: grade?.gradeId,
                            ...restValues,
                            items: items.map(t => ({
                                examPlanId: reqParams.examPlanId,
                                examGradeId,
                                gradeId: grade?.gradeId,
                                classNumber: t.classNumber,
                                nceeCourseCombId: t.nceeCourseCombId,
                                certificateType: t.certificateType ? JSON.parse(`${t.certificateType}`) : CertificateType.NONE,
                                idNumber: t.idNumber?.toUpperCase(),
                                name: t.name,
                                gender: t.gender ? JSON.parse(`${t.gender}`) : Gender.UNKNOWN,
                                examNumber: t.examNumber,
                                studentNumber: t.studentNumber,
                                roomNumber: t.roomNumber,
                                seatNumber: t.seatNumber,
                                remark: t.remark,
                            })),
                            dataImportMode: DataImportMode.CLEAR_APPEND,
                        });
                        message.success('导入成功');
                        handleBack();
                    }
                    catch { }
                }
            });
        }
        catch {
            message.error('年级或校区未选择');
            window.scrollTo({ top: 0, behavior: 'smooth' });
        }
    }

    const columns: ProColumns<API.UploadExamStudentOutput>[] = [
        {
            title: '验证',
            valueType: 'option',
            width: 48,
            align: 'center',
            render: (_, r) => {
                if (r.isSuccess) {
                    return (<StatusIcon status="success" filled />);
                }
                return (
                    <Tooltip title={r.errorMessage}>
                        <StatusIcon status="error" filled />
                    </Tooltip>
                );
            },
        },
        {
            title: '行号',
            valueType: 'option',
            render: (v, _, index) => {
                return <Typography.Text type="secondary">{index + 1}</Typography.Text>;
            },
            width: 48,
            align: 'center',
        },
        {
            title: '班级',
            dataIndex: 'classNumber',
            width: 48,
            align: 'center',
        },
        {
            title: '姓名',
            dataIndex: 'name',
            align: 'center',
            width: 120,
            // className: 'minw-80',
        },
        // {
        //     title: '证件类型',
        //     dataIndex: 'certificateTypeName',
        //     width: 112,
        //     align: 'center',
        // },
        {
            title: '证件类型',
            dataIndex: 'certificateType',
            valueEnum: getDictValueEnum('certificate_type'),
            width: 120,
            align: 'center',
        },
        {
            title: '证件号码',
            dataIndex: 'idNumber',
            width: 160,
            align: 'center',
        },
        {
            title: '性别',
            dataIndex: 'gender',
            valueEnum: getDictValueEnum('gender'),
            width: 48,
            align: 'center',
            hideInSearch: true,
        },
        {
            title: '自编监测号',
            dataIndex: 'examNumber',
            width: 112,
            align: 'center',
        },
        ...(baseData?.hasNceeCourseComb ? [{
            title: '选科组合',
            dataIndex: 'nceeCourseCombName',
            width: 80,
            align: 'center',
            hideInSearch: true,
        } as ProColumns] : []),
        {
            title: '校验结果',
            dataIndex: 'errorMessage',
            ellipsis: true,
            hideInSearch: true,
            width: 280,
            render: (_, r) => {
                if (r.isSuccess) {
                    return '通过';
                }
                return `${r.errorMessage?.join('、')}有误`;
            },
        },
        {
            title: '备注',
            dataIndex: 'remark',
            ellipsis: true,
            hideInSearch: true,
            width: 96,
        },
        {
            title: '考场号',
            dataIndex: 'roomNumber',
            width: 64,
            align: 'center',
        },
        {
            title: '座位号',
            dataIndex: 'seatNumber',
            width: 64,
            align: 'center',
        },
        {
            title: '操作',
            valueType: 'option',
            fixed: 'right',
            width: 112,
            align: 'center',
            render: (_, r) => {
                return (
                    <>
                        <Button type="link" size="small" onClick={() => {
                            currentRef.current = { ...r };
                            setEditOpen(true);
                        }}>修改</Button>
                        <Button type="link" size="small" onClick={() => handleDelete(r.rowNumber)}>删除</Button>
                    </>
                );
            },
        },
    ];

    return (
        <PageContainer
            title="监测学生批量导入"
            onBack={handleBack}
            extra={
                <Button
                    type="link"
                    icon={<BulbOutlined />}
                    onClick={() => {
                        window.scrollTo({ top: 0 });
                        setTourOpen(true);
                    }}
                >查看操作指引</Button>
            }
            loading={loading}
        >
            <ProCard
                title={<CardStepTitle>第一步：选择年级</CardStepTitle>}
                ref={tourGradeRef}
            >
                <Alert type="warning" showIcon message="每个年级所有班级学生填写在一个批量导入文件中，每个年级分开导入，有几个年级导入几次！" closable style={{ marginBottom: token.margin, color: token.colorError }} />
                <ProForm<ImportFormData>
                    layout="inline"
                    submitter={false}
                    formRef={formRef}
                    scrollToFirstError={true}
                >
                    <ProFormSelect
                        label="年级"
                        name="examGradeId"
                        options={baseData?.examGrades?.sort((a, b) => a.grade.gradeNumber - b.grade.gradeNumber)?.map(t => ({ label: `${t.grade.fullName}（${t.gradeBeginName}）`, value: t.id }))}
                        style={{ width: 240 }}
                        required
                        rules={[{ required: true, message: '年级必须选择' }]}
                        onChange={(e: number) => {
                            const g = baseData?.examGrades.find(t => t.id === e);
                            setGrade(g);
                        }}
                    />
                    {grade && grade.isRequiredSelfExamNumber &&
                        <Alert
                            type="warning"
                            message={`该年级必须自编监测号（长度为${grade.selfExamNumberLength}位）`}
                            showIcon
                            style={{
                                marginRight: token.marginLG,
                            }}
                        />
                    }
                    {baseData?.branches && baseData.branches.length > 0 &&
                        <ProFormSelect
                            label="校区"
                            name="sysOrgBranchId"
                            options={baseData.branches.map(t => ({ label: t.name, value: t.id }))}
                            style={{ width: 240 }}
                            required
                            rules={[{ required: true, message: '校区必须选择' }]}
                        />
                    }
                </ProForm>
            </ProCard>
            <ProCard
                title={<CardStepTitle>第二步：下载模板</CardStepTitle>}
                extra={
                    <Button
                        type="primary"
                        ref={tourDownloadRef}
                        onClick={() => {
                            window.open('/doc-templates/学生信息上报-填报模板.xlsx');
                        }}
                    >下载模板</Button>
                }
                style={{ marginTop: token.margin }}
            >
                <Typography.Paragraph>
                    <Typography.Text type="warning" strong>批量上传文件填写说明及注意事项：</Typography.Text>
                </Typography.Paragraph>
                <Typography.Paragraph>
                    <Typography.Text strong>模板格式：</Typography.Text>
                    模板文件中第一行为填写说明，第二行为标题行（从A至H列分别为班级、姓名、证件类型、证件号码、性别、自编监测号、选科组合、备注）。
                    <Typography.Text type="danger">填报数据必须在第一个工作表，并不能删除填写说明和标题行，不能删除和添加表格列！</Typography.Text>
                </Typography.Paragraph>
                <Typography.Paragraph>
                    <Typography.Text strong>A. 班级</Typography.Text>
                    （<Typography.Text type="danger">必填</Typography.Text>）：
                    填写班级数字序号，
                    <Typography.Text mark>如幼儿园中一班填1、中二班填2、大一班填1，小学三年级1班填1。</Typography.Text>
                </Typography.Paragraph>
                <Typography.Paragraph>
                    <Typography.Text strong>B. 姓名</Typography.Text>
                    （<Typography.Text type="danger">必填</Typography.Text>）：
                    学生真实姓名。
                </Typography.Paragraph>
                <Typography.Paragraph>
                    <Typography.Text strong>C. 证件类型</Typography.Text>
                    （<Typography.Text type="danger">必填</Typography.Text>）：
                    有居民身份证时，必须选择居民身份证，特殊情况可选择其他证件类型。
                </Typography.Paragraph>
                <Typography.Paragraph>
                    <Typography.Text strong>D. 证件号码</Typography.Text>：
                    有证件类型时必须填写，居民身份证为18位系统会进行严格的验证。
                </Typography.Paragraph>
                <Typography.Paragraph>
                    <Typography.Text strong>E. 性别</Typography.Text>：
                    证件类型选择为居民身份证时会自动处理。
                </Typography.Paragraph>
                <Typography.Paragraph>
                    <Typography.Text strong>F. 自编监测号</Typography.Text>：
                    一般情况不需要填写，有统一要求时才需要填写。
                </Typography.Paragraph>
                <Typography.Paragraph>
                    <Typography.Text strong>G. 选科组合</Typography.Text>：
                    <Typography.Text mark>仅高中阶段已选科学生需要填写</Typography.Text>，
                    学前、小学和初中不需要填写。
                </Typography.Paragraph>
                <Typography.Paragraph>
                    <Typography.Text strong>H. 备注</Typography.Text>：
                    有特殊情况自行填写。
                </Typography.Paragraph>
                <Typography.Paragraph>
                    <Typography.Text strong>I. 考场号</Typography.Text>：
                    有自编监测号时，学校有需要自行填写。
                </Typography.Paragraph>
                <Typography.Paragraph>
                    <Typography.Text strong>J. 座位号</Typography.Text>：
                    有自编监测号时，学校有需要自行填写。
                </Typography.Paragraph>
            </ProCard>

            <ProCard
                title={
                    <CardStepTitle>
                        第三步：上传文件
                        {!grade && <Typography.Text type="danger">（请先选择年级！）</Typography.Text>}
                    </CardStepTitle>}
                style={{ marginTop: token.margin }}
                ref={tourChooseFileRef}
            >
                <Space direction="vertical" style={{ width: '100%' }}>
                    <Upload.Dragger {...uploadProps} disabled={!grade}>
                        <p className="ant-upload-drag-icon"><InboxOutlined /></p>
                        <p className="ant-upload-text">点击或拖入文件到此处</p>
                    </Upload.Dragger>

                    <Space>
                        <Button
                            type="primary"
                            disabled={fileList.length === 0}
                            loading={uploading}
                            onClick={handleUpload}
                            ref={tourUploadRef}
                        >{uploading ? '上传中' : '立即上传'}</Button>
                        <UploadWrongLocalHeaderError />
                    </Space>

                    {data?.structureCorrect === false &&
                        <Alert
                            type="error"
                            showIcon
                            message={data?.errorMessage?.join('')}
                        />
                    }
                </Space>
            </ProCard>

            <ProCard
                style={{ marginTop: token.margin }}
                title={<CardStepTitle>第四步：确认数据</CardStepTitle>}
            >
                {/* <p className="ant-upload-text">根据表格验证提示修改数据无误后提交导入</p> */}
                <div ref={tourStuCountRef}>
                    <Typography.Title level={5}>1.人数统计</Typography.Title>
                    <Table
                        pagination={false}
                        scroll={{ x: 'max-content' }}
                        size="small"
                        bordered
                        rowKey="classNumber"
                        columns={[
                            { title: '班级', dataIndex: 'classNumber', width: 80, align: 'center', },
                            { title: '学生人数', dataIndex: 'total', width: 80, align: 'center' },
                            {
                                title: '验证通过',
                                dataIndex: 'success',
                                width: 120,
                                align: 'center',
                                render: (v) => <Typography.Text type="success">{v}</Typography.Text>,
                            },
                            {
                                title: '验证失败',
                                dataIndex: 'error',
                                width: 120,
                                align: 'center',
                                render: (v) => v > 0 ? <Typography.Text type="danger">{v}</Typography.Text> : null,
                            },
                            {},
                        ]}
                        dataSource={classTotal}
                        summary={(rows) => {
                            const total = rows.map(t => t.total).reduce((p, n) => p + n, 0);
                            const success = rows.map(t => t.success).reduce((p, n) => p + n, 0);
                            const error = rows.map(t => t.error).reduce((p, n) => p + n, 0);
                            return (
                                <Table.Summary.Row style={{ fontStyle: 'italic', fontWeight: 'bold' }}>
                                    <Table.Summary.Cell index={0} align="center">合计</Table.Summary.Cell>
                                    <Table.Summary.Cell index={1} align="center">{total}</Table.Summary.Cell>
                                    <Table.Summary.Cell index={2} align="center">
                                        <Typography.Text type="success">{success}</Typography.Text>
                                    </Table.Summary.Cell>
                                    <Table.Summary.Cell index={3} align="center">
                                        <Typography.Text type="danger">{error || ''}</Typography.Text>
                                    </Table.Summary.Cell>
                                    <Table.Summary.Cell index={4} align="center"></Table.Summary.Cell>
                                </Table.Summary.Row>
                            );
                        }}
                    />
                </div>
                <div ref={tourStuDetailRef}>
                    <ProTable<API.UploadExamStudentOutput>
                        actionRef={actionRef}
                        cardProps={false}
                        columns={columns}
                        size="small"
                        rowKey="rowNumber"
                        bordered
                        options={false}
                        sticky={{ offsetHeader: 56 }}
                        dataSource={[...data?.rows ?? []]}
                        virtual
                        scroll={{ y: Math.min(document.body.clientHeight - 56 - 24, 800) }}
                        pagination={false}
                        rowClassName={(r) => {
                            if (!r.isSuccess) {
                                return 'yb-row-error';
                            }
                            return '';
                        }}
                        toolbar={{
                            title: <Typography.Title level={5} style={{ marginBottom: 0 }}>2.学生明细</Typography.Title>,
                            subTitle: '有校验错误的数据，点击对应行操作中的修改进行修改。',
                            actions: [
                                // <Radio.Group
                                //     key="importType"
                                //     options={getDictOptions('data_import_mode')}
                                //     value={dataImportMode}
                                //     onChange={e => setDataImportMode(e.target.value)}
                                // />,
                                <Typography.Text key="tooltip" type="warning">重要提示：导入前会删除所选校区（若有）年级已填报学生！</Typography.Text>,
                                <Button
                                    key="import"
                                    type="primary"
                                    disabled={!data?.structureCorrect || uploading}
                                    onClick={handleImport}
                                    ref={tourSubmitRef}
                                >确认导入</Button>
                            ],
                        }}
                        search={false}
                    />
                </div>
            </ProCard>

            <Tour
                steps={[
                    {
                        title: '选择年级',
                        description: '导入前必须选择年级，如果有多个校区的学校必须选择校区。',
                        target: () => tourGradeRef.current,
                    },
                    {
                        title: '下载模板',
                        description: '下载批量导入监测学生模板文件，请按模板填写说明及注意事项填写文件。',
                        target: () => tourDownloadRef.current,
                    },
                    {
                        title: '选择文件',
                        description: '拖动文件至此区域，或点击该区域选择文件上传。',
                        target: () => tourChooseFileRef.current,
                    },
                    {
                        title: '上传文件',
                        description: '选择好批量导入文件后，点击此按钮上传文件，后台解析后返回校验结果和数据。',
                        target: () => tourUploadRef.current,
                    },
                    {
                        title: '人数统计',
                        description: '上传文件后会显示各班级人数、验证通过和失败的数量。',
                        target: () => tourStuCountRef.current,
                    },
                    {
                        title: '学生明细',
                        description: '所有上传的学生明细，请根据校验结果修改数据。',
                        target: () => tourStuDetailRef.current,
                    },
                    {
                        title: '确认导入',
                        description: '检查修改确认批量导入学生信息无误后确认导入。',
                        target: () => tourSubmitRef.current,
                    },
                ]}
                open={tourOpen}
                onClose={() => setTourOpen(false)}
            />

            {editOpen && currentRef.current &&
                <ExamStudentImportEditModal
                    isRequiredSelfExamNumber={grade?.isRequiredSelfExamNumber}
                    selfExamNumberLength={grade?.selfExamNumberLength}
                    data={currentRef.current}
                    hasNceeCourseComb={baseData?.hasNceeCourseComb}
                    onFinish={handleEdit}
                    onClose={() => setEditOpen(false)}
                />
            }

            {/* <FloatButton.BackTop visibilityHeight={100} /> */}
        </PageContainer>
    );
}

export default OrgExamStudentImport;
