<script setup lang="ts">
import { computed, ref, watch } from "vue";

import type {
  Candidate,
  CustomStrategy,
  FormulaCondition,
  FormulaScore,
  ScreenerFormula,
  ScreenerRun,
} from "../../shared/api/screener";
import CandidateTable from "./CandidateTable.vue";

const props = defineProps<{
  factors: Record<string, string>;
  factorGroups: Record<string, string[]>;
  strategies: CustomStrategy[];
  runs: ScreenerRun[];
  compiledFormula: ScreenerFormula | null;
  locked: boolean;
  busy: boolean;
}>();
const emit = defineEmits<{
  save: [name: string, formula: ScreenerFormula];
  run: [strategy: CustomStrategy];
  remove: [strategy: CustomStrategy];
  track: [run: ScreenerRun, candidate: Candidate];
  compile: [description: string];
}>();

const name = ref("我的选股策略");
const naturalLanguage = ref("");
const selectedFactor = ref("return_20d");
const scores = ref<FormulaScore[]>([
  { field: "return_20d", weight: 60, direction: "desc" },
  { field: "sector_strength", weight: 40, direction: "desc" },
]);
const filters = ref<FormulaCondition[]>([
  { field: "amount_billion", op: ">=", value: 1 },
]);
const listedDays = ref(120);
const outputLimit = ref(30);
const minimumScore = ref(50);
const excludeSt = ref(true);
const selected = ref<number | null>(props.strategies[0]?.id ?? null);
const current = computed(() => props.strategies.find((item) => item.id === selected.value));
const run = computed(() =>
  props.runs.find((item) => item.strategy_id === `custom-${selected.value}`),
);
const total = computed(() =>
  scores.value.reduce((sum, item) => sum + Number(item.weight), 0),
);

watch(
  () => props.strategies,
  (items) => {
    if (!items.some((item) => item.id === selected.value)) selected.value = items[0]?.id ?? null;
  },
);

watch(
  () => props.compiledFormula,
  (formula) => { if (formula) applyFormula(formula); },
);

function addFactor(): void {
  if (!selectedFactor.value || scores.value.some((item) => item.field === selectedFactor.value)) {
    return;
  }
  scores.value.push({ field: selectedFactor.value, weight: 0, direction: "desc" });
}

function addFilter(): void {
  filters.value.push({ field: "amount_billion", op: ">=", value: 1 });
}

function applyFormula(formula: ScreenerFormula): void {
  scores.value = formula.score.map((item) => ({
    ...item,
    weight: Math.round(item.weight * 100),
  }));
  filters.value = formula.filters.map((item) => ({ ...item }));
  listedDays.value = formula.universe.listed_days_min;
  excludeSt.value = formula.universe.exclude_st;
  outputLimit.value = formula.limit;
  minimumScore.value = Math.round(formula.min_score * 100);
}

function edit(strategy: CustomStrategy): void {
  selected.value = strategy.id;
  name.value = strategy.name;
  applyFormula(strategy.formula);
}

function save(): void {
  emit("save", name.value, {
    universe: {
      exclude_st: excludeSt.value,
      listed_days_min: Number(listedDays.value),
    },
    filters: filters.value.map((item) => ({ ...item, value: Number(item.value) })),
    score: scores.value.map((item) => ({
      ...item,
      weight: Number(item.weight) / 100,
    })),
    limit: Number(outputLimit.value),
    min_score: Number(minimumScore.value) / 100,
  });
}
</script>

<template>
  <section class="custom-builder card" :class="{ 'locked-content': locked }" :aria-disabled="locked">
    <div class="custom-factors">
      <header class="card-header">
        <h2>因子与权重</h2>
        <span :class="['tag', { warning: total !== 100 }]">合计 {{ total }}%</span>
      </header>
      <div class="factor-add">
        <select v-model="selectedFactor" class="select">
          <optgroup v-for="(fields, group) in factorGroups" :key="group" :label="group">
            <option v-for="field in fields" :key="field" :value="field">
              {{ factors[field] }}
            </option>
          </optgroup>
        </select>
        <button class="btn" type="button" @click="addFactor">添加因子</button>
      </div>
      <div class="factor-list">
        <div v-for="(item, index) in scores" :key="item.field">
          <label>{{ factors[item.field] }}</label>
          <select v-model="item.direction" class="select factor-direction">
            <option value="desc">高优</option><option value="asc">低优</option>
          </select>
          <input v-model.number="item.weight" type="range" min="0" max="100">
          <input v-model.number="item.weight" class="input numeric" type="number" min="0" max="100">
          <button class="icon-button" type="button" title="移除因子" @click="scores.splice(index, 1)">×</button>
        </div>
      </div>
    </div>
    <div class="custom-filters">
      <header class="card-header"><h2>过滤与输出</h2></header>
      <div class="formula-compiler">
        <label class="field"><span>自然语言转公式</span><textarea v-model="naturalLanguage" class="input" rows="2" maxlength="500" placeholder="例如：近20日走势较强、成交额不少于3亿元，偏重板块强度"></textarea></label>
        <button class="btn" type="button" :disabled="busy || naturalLanguage.trim().length < 5" @click="emit('compile', naturalLanguage)">{{ busy ? "转换中" : "转换" }}</button>
      </div>
      <div class="filter-list">
        <div v-for="(item, index) in filters" :key="index">
          <select v-model="item.field" class="select">
            <option v-for="(label, field) in factors" :key="field" :value="field">{{ label }}</option>
          </select>
          <select v-model="item.op" class="select"><option>&gt;=</option><option>&gt;</option><option>&lt;=</option><option>&lt;</option><option>==</option><option>!=</option></select>
          <input v-model.number="item.value" class="input numeric" type="number">
          <button class="icon-button" type="button" title="移除条件" @click="filters.splice(index, 1)">×</button>
        </div>
        <button class="btn btn-small" type="button" @click="addFilter">添加条件</button>
      </div>
      <div class="custom-options">
        <label class="field"><span>上市天数</span><input v-model.number="listedDays" class="input numeric" type="number" min="0" max="5000"></label>
        <label class="field"><span>输出数量</span><input v-model.number="outputLimit" class="input numeric" type="number" min="1" max="50"></label>
        <label class="field"><span>最低综合分（%）</span><input v-model.number="minimumScore" class="input numeric" type="number" min="0" max="100"></label>
        <label class="switch-field"><input v-model="excludeSt" type="checkbox"><span>剔除ST与退市风险</span></label>
      </div>
      <div class="custom-save">
        <label class="field"><span>策略名称</span><input v-model="name" class="input" maxlength="30"></label>
        <button class="btn btn-primary" type="button" :disabled="busy || total !== 100 || !scores.length" @click="save">保存策略</button>
      </div>
    </div>
  </section>
  <section class="card custom-library" :class="{ 'locked-content': locked }" :aria-disabled="locked">
    <header class="card-header"><h2>我的策略</h2><span class="tag">手动执行</span></header>
    <div class="custom-strategy-list">
      <button v-for="item in strategies" :key="item.id" type="button" :class="{ active: selected === item.id }" @click="selected = item.id">
        <strong>{{ item.name }}</strong><span>第 {{ item.version }} 版</span>
      </button>
      <div v-if="!strategies.length" class="screener-empty"><span>保存后的自定义策略会出现在这里。</span></div>
    </div>
    <div v-if="current" class="custom-actions">
      <button class="btn btn-primary" type="button" :disabled="busy" @click="emit('run', current)">执行选股</button>
      <button class="btn" type="button" :disabled="busy" @click="edit(current)">编辑</button>
      <button class="btn" type="button" :disabled="busy" @click="emit('remove', current)">删除</button>
    </div>
    <div v-if="run?.backtest" class="notice">
      <template v-if="run.backtest.stable">历史样本 {{ run.backtest.sample_size }} · 条件胜率 {{ run.backtest.win_rate?.toFixed(1) }}% · 平均3日收益 {{ run.backtest.average_return_3d?.toFixed(2) }}%</template>
      <template v-else>{{ run.backtest.message }}</template>
    </div>
  </section>
  <CandidateTable :run="run" :locked="locked" @track="(candidate) => run && emit('track', run, candidate)" />
</template>
