<script setup lang="ts">
import {
  Banknote,
  CalendarDays,
  CloudCog,
  Download,
  FileSpreadsheet,
  Loader2,
  Play,
  Trash2,
  Upload,
  UsersRound,
} from "@lucide/vue";
import { computed, ref } from "vue";

import { ApiError } from "../api/http";
import {
  calculateMonthlyFromDingTalk,
  calculateMonthlyFromExcel,
  exportMonthlyRun,
} from "../api/monthlyPayroll";
import type { MonthlyPayrollDetailResponse } from "../api/types";
import DatePicker from "../components/DatePicker.vue";
import ResultsTable from "../components/ResultsTable.vue";
import StatCard from "../components/StatCard.vue";
import { useAuthStore } from "../stores/auth";
import {
  extractMonthFromExcelFilename,
  formatMonthRange,
  isSalaryMonth,
  type ExcelMonthInfo,
} from "../utils/payrollMonth";

const auth = useAuthStore();
const selectedFile = ref<File | null>(null);
const selectedFileMonth = ref<ExcelMonthInfo | null>(null);
const salaryMonth = ref(defaultSalaryMonth());
const exportExcel = ref(true);
const activeDetail = ref<MonthlyPayrollDetailResponse | null>(null);
const loading = ref<"excel" | "dingtalk" | "">("");
const errorMessage = ref("");
const successMessage = ref("");

const canCalculate = computed(() => auth.hasPermission("monthly_payroll:calculate"));
const activeRun = computed(() => activeDetail.value?.run);
const monthRange = computed(() => formatMonthRange(salaryMonth.value));
const hasValidMonth = computed(() => isSalaryMonth(salaryMonth.value));
const excelMonthMismatch = computed(
  () => Boolean(selectedFile.value && selectedFileMonth.value && selectedFileMonth.value.month !== salaryMonth.value),
);
const dingtalkScopeText = computed(() =>
  hasValidMonth.value ? `将同步 ${monthRange.value} 的钉钉考勤` : "请选择核算月份后再同步钉钉",
);
const excelMonthHint = computed(() => {
  if (!selectedFile.value) {
    return "选择 Excel 后会自动识别文件月份。";
  }
  if (!selectedFileMonth.value) {
    return "未从文件名识别月份，请确认核算月份与 Excel 内容一致。";
  }
  if (excelMonthMismatch.value) {
    return `Excel 文件月份为 ${selectedFileMonth.value.month}，当前核算月份为 ${salaryMonth.value || "未选择"}，请保持一致后再导入。`;
  }
  return `Excel 文件月份：${selectedFileMonth.value.month}（${selectedFileMonth.value.rangeLabel}）`;
});
const totalOvertime = computed(() => (activeRun.value?.overtime_total || 0).toFixed(1));
const totalDeduction = computed(() => money(activeRun.value?.deduction_total || 0));
const totalNetSalary = computed(() => money(activeRun.value?.net_total || 0));

function defaultSalaryMonth(): string {
  const now = new Date();
  const previousMonth = new Date(now.getFullYear(), now.getMonth() - 1, 1);
  const year = previousMonth.getFullYear();
  const month = String(previousMonth.getMonth() + 1).padStart(2, "0");
  return `${year}-${month}`;
}

function handleFileChange(event: Event): void {
  const input = event.target as HTMLInputElement;
  selectedFile.value = input.files?.[0] || null;
  selectedFileMonth.value = selectedFile.value ? extractMonthFromExcelFilename(selectedFile.value.name) : null;
  errorMessage.value = "";
  successMessage.value = "";

  if (selectedFileMonth.value && salaryMonth.value !== selectedFileMonth.value.month) {
    salaryMonth.value = selectedFileMonth.value.month;
    successMessage.value = `已根据文件识别核算月份：${selectedFileMonth.value.month}`;
  }
}

async function submitExcel(): Promise<void> {
  if (!selectedFile.value) {
    errorMessage.value = "请选择钉钉月度汇总 Excel 文件";
    return;
  }
  if (!hasValidMonth.value) {
    errorMessage.value = "请选择核算月份";
    return;
  }
  if (excelMonthMismatch.value) {
    errorMessage.value = excelMonthHint.value;
    return;
  }

  await runCalculation("excel", () => calculateMonthlyFromExcel(selectedFile.value!, salaryMonth.value, exportExcel.value));
}

async function submitDingTalk(): Promise<void> {
  if (!hasValidMonth.value) {
    errorMessage.value = "请选择核算月份";
    return;
  }

  await runCalculation("dingtalk", () => calculateMonthlyFromDingTalk(salaryMonth.value, exportExcel.value));
}

async function runCalculation(
  source: "excel" | "dingtalk",
  executor: () => Promise<MonthlyPayrollDetailResponse>,
): Promise<void> {
  loading.value = source;
  errorMessage.value = "";
  successMessage.value = "";

  try {
    activeDetail.value = await executor();
    successMessage.value = `核算完成：${activeDetail.value.run.salary_month}，${activeDetail.value.run.employee_count} 名员工`;
  } catch (error) {
    errorMessage.value = error instanceof ApiError ? error.message : "核算失败，请检查数据后重试";
  } finally {
    loading.value = "";
  }
}

async function downloadCurrent(): Promise<void> {
  if (!activeRun.value) {
    return;
  }
  await exportMonthlyRun(activeRun.value.id);
}

function clearResult(): void {
  activeDetail.value = null;
  successMessage.value = "";
  errorMessage.value = "";
}

function sourceText(sourceType: string | undefined): string {
  const map: Record<string, string> = {
    excel: "Excel导入",
    dingtalk: "钉钉同步",
  };
  return sourceType ? map[sourceType] || sourceType : "未核算";
}

function money(value: number): string {
  return new Intl.NumberFormat("zh-CN", {
    style: "currency",
    currency: "CNY",
    maximumFractionDigits: 2,
  }).format(value);
}
</script>

<template>
  <div class="view-stack payroll-import-view">
    <header class="page-header">
      <div>
        <h1>同步导入</h1>
        <p>按月份导入考勤并生成工资核算结果。</p>
      </div>
      <div class="header-actions">
        <button class="secondary-button" type="button" :disabled="!activeDetail" @click="clearResult">
          <Trash2 :size="18" aria-hidden="true" />
          <span>清空结果</span>
        </button>
        <button class="primary-button" type="button" :disabled="!activeRun" @click="downloadCurrent">
          <Download :size="18" aria-hidden="true" />
          <span>下载结果</span>
        </button>
      </div>
    </header>

    <section class="panel payroll-settings-panel">
      <div class="panel-header">
        <div>
          <h2>核算设置</h2>
          <p>核算月份会同时决定钉钉同步范围和 Excel 入库月份。</p>
        </div>
        <span class="status-chip green">API 已连接</span>
      </div>

      <div class="settings-grid">
        <label class="field">
          <span>核算月份</span>
          <DatePicker v-model="salaryMonth" mode="month" placeholder="请选择核算月份" />
        </label>
        <div class="readonly-field">
          <span>核算周期</span>
          <strong>{{ monthRange }}</strong>
        </div>
        <div class="readonly-field">
          <span>同步范围</span>
          <strong>{{ dingtalkScopeText }}</strong>
        </div>
        <label class="checkbox-card">
          <input v-model="exportExcel" type="checkbox" />
          <span>生成 Excel 结果文件</span>
        </label>
      </div>
    </section>

    <section class="source-workflow" aria-label="数据来源">
      <div class="section-title-row">
        <div>
          <h2>选择导入方式</h2>
          <p>两种方式都会生成所选月份的同一套月度核算结果。</p>
        </div>
      </div>

      <div class="source-strip">
        <article class="source-option">
          <div class="source-option-main">
            <span class="action-icon blue">
              <CloudCog :size="22" aria-hidden="true" />
            </span>
            <div>
              <h2>钉钉同步</h2>
              <p>{{ dingtalkScopeText }}</p>
            </div>
          </div>
          <button class="primary-button" type="button" :disabled="!canCalculate || !hasValidMonth || loading === 'dingtalk'" @click="submitDingTalk">
            <Loader2 v-if="loading === 'dingtalk'" class="spin" :size="18" aria-hidden="true" />
            <Play v-else :size="18" aria-hidden="true" />
            <span>{{ loading === "dingtalk" ? "同步中" : "开始同步" }}</span>
          </button>
        </article>

        <article class="source-option">
          <div class="source-option-main">
            <span class="action-icon green">
              <FileSpreadsheet :size="22" aria-hidden="true" />
            </span>
            <div>
              <h2>Excel 导入</h2>
              <p>{{ selectedFile?.name || "上传钉钉月度汇总表后开始核算。" }}</p>
              <small class="source-note" :class="{ warning: excelMonthMismatch }">{{ excelMonthHint }}</small>
            </div>
          </div>
          <div class="source-actions">
            <label class="file-button secondary-file-button">
              <Upload :size="18" aria-hidden="true" />
              <span>{{ selectedFile ? "更换文件" : "选择文件" }}</span>
              <input accept=".xlsx,.xls" type="file" @change="handleFileChange" />
            </label>
            <button class="secondary-button" type="button" :disabled="!canCalculate || !hasValidMonth || loading === 'excel' || !selectedFile || excelMonthMismatch" @click="submitExcel">
              <Loader2 v-if="loading === 'excel'" class="spin" :size="18" aria-hidden="true" />
              <Play v-else :size="18" aria-hidden="true" />
              <span>{{ loading === "excel" ? "核算中" : "开始导入" }}</span>
            </button>
          </div>
        </article>
      </div>
    </section>

    <p v-if="errorMessage" class="form-error">{{ errorMessage }}</p>
    <p v-if="successMessage" class="form-success">{{ successMessage }}</p>

    <section v-if="activeRun" class="summary-strip">
      <StatCard title="工资月份" :value="activeRun.salary_month" :icon="CalendarDays" tone="blue" :meta="sourceText(activeRun.source_type)" />
      <StatCard title="员工数量" :value="String(activeRun.employee_count)" :icon="UsersRound" tone="neutral" meta="参与核算" />
      <StatCard title="剩余加班合计" :value="`${totalOvertime}h`" :icon="CloudCog" tone="green" meta="加班-请假" />
      <StatCard title="扣款合计" :value="totalDeduction" :icon="Trash2" tone="red" meta="迟到+缺卡" />
      <StatCard title="实发合计" :value="totalNetSalary" :icon="Banknote" tone="neutral" meta="已计算" />
    </section>

    <ResultsTable :results="activeDetail?.results || []" />
  </div>
</template>
