<script setup lang="tsx">
import { computed, ref } from 'vue';
import { NButton, NDivider, NInput, NSpace } from 'naive-ui';
import { jsonClone } from '@sa/utils';
import {
  fetchBatchDeleteHistoryScoreControlLine,
  fetchCreateHistoryScoreControlLine,
  fetchGetHistoryScoreControlLineList,
  fetchUpdateHistoryScoreControlLine
} from '@/service/api/art/history-score-control-line';
import { useAppStore } from '@/store/modules/app';
import { useAuth } from '@/hooks/business/auth';
import { useDownload } from '@/hooks/business/download';
import { defaultTransform, useNaivePaginatedTable } from '@/hooks/common/table';
import { $t } from '@/locales';
import ButtonIcon from '@/components/custom/button-icon.vue';
import InlineExpandTextarea from '@/components/custom/inline-expand-textarea.vue';
import HistoryScoreControlLineSearch from './modules/history-score-control-line-search.vue';

defineOptions({
  name: 'HistoryScoreControlLineList'
});

const appStore = useAppStore();
const { download } = useDownload();
const { hasAuth } = useAuth();

const searchParams = ref<Api.Art.HistoryScoreControlLineSearchParams>({
  pageNum: 1,
  pageSize: 10,
  provinceCode: null,
  provinceName: null,
  year: null,
  majorCategory: null,
  batchName: null,
  subjectType: null,
  cultureScore: null,
  majorScore: null,
  cultureScoreExam: null,
  majorScoreExam: null,
  params: {}
});

type TableRow = Api.Art.HistoryScoreControlLine & { tempKey?: string };
type Model = Api.Art.HistoryScoreControlLineOperateParams;
type EditableField = Extract<keyof Model, keyof TableRow>;

const editingModel = ref<Model>(createDefaultModel());
const editingSnapshot = ref<TableRow | null>(null);
const editingMode = ref<NaiveUI.TableOperateType | null>(null);
const editingRowKey = ref<string | null>(null);
const savingRowKey = ref<string | null>(null);
const tempRow = ref<TableRow | null>(null);
const checkedRowKeys = ref<CommonType.IdType[]>([]);

const editableColumns: Array<{ key: EditableField; title: string; textarea?: boolean }> = [
  { key: 'provinceCode', title: '省份行政区划代码' },
  { key: 'provinceName', title: '省份名称' },
  { key: 'year', title: '年份' },
  { key: 'majorCategory', title: '专业类别' },
  { key: 'batchName', title: '批次' },
  { key: 'subjectType', title: '科类(文/理)' },
  { key: 'cultureScore', title: '文化成绩分数' },
  { key: 'majorScore', title: '专业成绩分数' },
  { key: 'cultureScoreExam', title: '文化成绩校考分数' },
  { key: 'majorScoreExam', title: '专业成绩校考分数' },
  { key: 'remark', title: '备注', textarea: true }
];

const { columns, columnChecks, data, getData, getDataByPage, loading, mobilePagination, scrollX } =
  useNaivePaginatedTable({
    api: () => fetchGetHistoryScoreControlLineList(searchParams.value),
    transform: response => defaultTransform(response),
    onPaginationParamsChange: params => {
      searchParams.value.pageNum = params.page;
      searchParams.value.pageSize = params.pageSize;
    },
    columns: () => createColumns()
  });

const tableData = computed<TableRow[]>(() => {
  const rows = data.value as TableRow[];
  return tempRow.value ? [tempRow.value, ...rows] : rows;
});

function createColumns(): NaiveUI.TableColumn<TableRow>[] {
  return [
    {
      type: 'selection',
      align: 'center',
      width: 48
    },
    {
      key: 'index',
      title: $t('common.index'),
      align: 'center',
      width: 64,
      render: (_, index) => index + 1
    },
    {
      key: 'controlId',
      title: '省控线主键',
      align: 'center',
      minWidth: 120
    },
    ...editableColumns.map(column => createEditableColumn(column)),
    createOperateColumn()
  ];
}

function createEditableColumn(column: { key: EditableField; title: string; textarea?: boolean }) {
  return {
    key: column.key,
    title: column.title,
    align: 'center',
    minWidth: 140,
    render: (row: TableRow) => renderEditableCell(row, column.key, column)
  } satisfies NaiveUI.TableColumn<TableRow>;
}

function createOperateColumn(): NaiveUI.TableColumn<TableRow> {
  return {
    key: 'operate',
    title: $t('common.operate'),
    align: 'center',
    fixed: 'right',
    width: 180,
    render: (row: TableRow) => {
      const rowKey = resolveRowKey(row);
      const editing = editingRowKey.value === rowKey;
      const saving = savingRowKey.value === rowKey;

      if (editing) {
        return (
          <NSpace size={8} justify="center">
            <NButton size="tiny" quaternary disabled={saving} onClick={handleCancelEdit}>
              {$t('common.cancel')}
            </NButton>
            <NButton size="tiny" type="primary" loading={saving} onClick={handleSaveRow}>
              {$t('common.save')}
            </NButton>
          </NSpace>
        );
      }

      const showEdit = hasAuth('art:historyScoreControlLine:edit');
      const showDelete = hasAuth('art:historyScoreControlLine:remove');

      return (
        <div class="flex-center gap-8px">
          {showEdit ? (
            <NButton size="tiny" text type="primary" onClick={() => handleEditRow(row)}>
              {$t('common.edit')}
            </NButton>
          ) : null}
          {showEdit && showDelete ? <NDivider vertical /> : null}
          {showDelete ? (
            <ButtonIcon
              text
              type="error"
              icon="material-symbols:delete-outline"
              tooltipContent={$t('common.delete')}
              popconfirmContent={$t('common.confirmDelete')}
              onPositiveClick={() => handleDelete(row.controlId)}
            />
          ) : null}
        </div>
      );
    }
  };
}

function getRowFieldValue(row: TableRow, field: EditableField) {
  return row[field as keyof TableRow];
}

function formatDisplayValue(value: unknown) {
  if (value === null || value === undefined || value === '') {
    return '-';
  }
  return typeof value === 'number' ? value : String(value);
}

function renderEditableCell(row: TableRow, field: EditableField, options?: { textarea?: boolean }) {
  if (!isEditingRow(row)) {
    return formatDisplayValue(getRowFieldValue(row, field));
  }

  const inputValue = editingModel.value[field];
  const resolvedValue = inputValue === null || inputValue === undefined ? '' : String(inputValue);

  if (options?.textarea) {
    return renderTextareaEditor(row, field, resolvedValue);
  }

  return (
    <NInput
      size="small"
      type={options?.textarea ? 'textarea' : 'text'}
      autosize={options?.textarea ? { minRows: 1, maxRows: 4 } : undefined}
      value={resolvedValue}
      onUpdateValue={value => updateEditingField(field, value)}
    />
  );
}

function renderTextareaEditor(row: TableRow, field: EditableField, value: string) {
  return <InlineExpandTextarea value={value} onUpdateValue={val => updateEditingField(field, val)} />;
}

function updateEditingField(field: EditableField, value: string | number | null) {
  (editingModel.value as Record<string, string | number | null>)[field] = value;
}

function resolveRowKey(row: TableRow) {
  if (row.controlId !== null && row.controlId !== undefined && row.controlId !== '') {
    return String(row.controlId);
  }
  return row.tempKey ?? '';
}

function isEditingRow(row: TableRow) {
  return editingRowKey.value !== null && editingRowKey.value === resolveRowKey(row);
}

function createDefaultModel(): Model {
  return {
    controlId: null,
    provinceCode: '',
    provinceName: '',
    year: null,
    majorCategory: '',
    batchName: '',
    subjectType: '',
    cultureScore: null,
    majorScore: null,
    cultureScoreExam: null,
    majorScoreExam: null,
    remark: ''
  };
}

function createTempKey() {
  return `temp-${Date.now()}-${Math.random().toString(16).slice(2)}`;
}

function ensureEditingGuard(action: () => void | Promise<void>) {
  const executeAction = () => Promise.resolve(action());

  if (!editingRowKey.value) {
    return executeAction();
  }

  if (!window.$dialog) {
    resetEditingState();
    return executeAction();
  }

  return new Promise<void>((resolve, reject) => {
    window.$dialog?.warning({
      title: '提示',
      content: '当前行尚未保存，确定放弃修改吗？',
      positiveText: '放弃',
      negativeText: '继续编辑',
      onPositiveClick: async () => {
        resetEditingState();
        try {
          await executeAction();
          resolve();
        } catch (error) {
          reject(error);
        }
      },
      onNegativeClick: () => resolve()
    });
  });
}

function resetEditingState() {
  editingModel.value = createDefaultModel();
  editingSnapshot.value = null;
  editingMode.value = null;
  editingRowKey.value = null;
  savingRowKey.value = null;
  tempRow.value = null;
}

async function handleAddRow() {
  await ensureEditingGuard(() => {
    editingMode.value = 'add';
    editingModel.value = createDefaultModel();
    editingSnapshot.value = null;
    const key = createTempKey();
    tempRow.value = { ...(editingModel.value as TableRow), tempKey: key };
    editingRowKey.value = key;
    checkedRowKeys.value = [];
  });
}

async function handleEditRow(row: TableRow) {
  await ensureEditingGuard(() => {
    editingMode.value = 'edit';
    tempRow.value = null;
    editingRowKey.value = resolveRowKey(row);
    editingSnapshot.value = jsonClone(row);
    editingModel.value = Object.assign(createDefaultModel(), jsonClone(row));
  });
}

function handleCancelEdit() {
  resetEditingState();
}

const requiredFields: Array<{ key: EditableField; label: string }> = [
  { key: 'provinceCode', label: '省份行政区划代码' },
  { key: 'provinceName', label: '省份名称' },
  { key: 'year', label: '年份' },
  { key: 'majorCategory', label: '专业类别' },
  { key: 'batchName', label: '批次' },
  { key: 'subjectType', label: '科类(文/理)' }
];

function validateModel() {
  for (const item of requiredFields) {
    const value = editingModel.value[item.key];
    if (value === null || value === undefined || value === '') {
      window.$message?.warning(`${item.label}不能为空`);
      return false;
    }
  }
  return true;
}

async function handleSaveRow() {
  if (!editingMode.value) return;
  if (!validateModel()) return;

  const {
    controlId,
    provinceCode,
    provinceName,
    year,
    majorCategory,
    batchName,
    subjectType,
    cultureScore,
    majorScore,
    cultureScoreExam,
    majorScoreExam,
    remark
  } = editingModel.value;

  savingRowKey.value = editingRowKey.value;

  const requestResult =
    editingMode.value === 'add'
      ? await fetchCreateHistoryScoreControlLine({
          provinceCode,
          provinceName,
          year,
          majorCategory,
          batchName,
          subjectType,
          cultureScore,
          majorScore,
          cultureScoreExam,
          majorScoreExam,
          remark
        })
      : await fetchUpdateHistoryScoreControlLine({
          controlId,
          provinceCode,
          provinceName,
          year,
          majorCategory,
          batchName,
          subjectType,
          cultureScore,
          majorScore,
          cultureScoreExam,
          majorScoreExam,
          remark
        });

  savingRowKey.value = null;

  if (requestResult.error) {
    window.$message?.error(requestResult.error.message || '保存失败');
    if (editingMode.value === 'edit' && editingSnapshot.value) {
      editingModel.value = Object.assign(createDefaultModel(), jsonClone(editingSnapshot.value));
    }
    return;
  }

  window.$message?.success($t('common.updateSuccess'));
  resetEditingState();
  await getData();
}

async function handleBatchDelete() {
  await ensureEditingGuard(async () => {
    const { error } = await fetchBatchDeleteHistoryScoreControlLine(checkedRowKeys.value);
    if (error) return;
    window.$message?.success($t('common.deleteSuccess'));
    checkedRowKeys.value = [];
    await getData();
  });
}

async function handleDelete(controlId: CommonType.IdType) {
  await ensureEditingGuard(async () => {
    const { error } = await fetchBatchDeleteHistoryScoreControlLine([controlId]);
    if (error) return;
    window.$message?.success($t('common.deleteSuccess'));
    await getData();
  });
}

function handleExport() {
  download('/art/historyScoreControlLine/export', searchParams.value, `历年省控线_${new Date().getTime()}.xlsx`);
}

async function handleSearch() {
  await ensureEditingGuard(async () => {
    await getDataByPage();
  });
}

async function handleRefresh() {
  await ensureEditingGuard(getData);
}

function rowClassName(row: TableRow) {
  return isEditingRow(row) ? 'inline-edit-row' : '';
}
</script>

<template>
  <div class="min-h-500px flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto">
    <HistoryScoreControlLineSearch v-model:model="searchParams" @search="handleSearch" />
    <NCard title="历年省控线列表" :bordered="false" size="small" class="card-wrapper sm:flex-1-hidden">
      <template #header-extra>
        <TableHeaderOperation
          v-model:columns="columnChecks"
          :disabled-delete="checkedRowKeys.length === 0"
          :loading="loading"
          :show-add="hasAuth('art:historyScoreControlLine:add')"
          :show-delete="hasAuth('art:historyScoreControlLine:remove')"
          :show-export="hasAuth('art:historyScoreControlLine:export')"
          @add="handleAddRow"
          @delete="handleBatchDelete"
          @export="handleExport"
          @refresh="handleRefresh"
        />
      </template>
      <NDataTable
        v-model:checked-row-keys="checkedRowKeys"
        :columns="columns"
        :data="tableData"
        size="small"
        :flex-height="!appStore.isMobile"
        :scroll-x="scrollX"
        :loading="loading"
        remote
        :row-key="resolveRowKey"
        :row-class-name="rowClassName"
        :pagination="mobilePagination"
        class="sm:h-full"
      />
    </NCard>
  </div>
</template>

<style scoped>
:deep(.inline-edit-row .n-data-table-td) {
  background-color: rgba(24, 160, 88, 0.08);
}
</style>
