<script setup lang="ts">
import { computed, onMounted, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { ElMessage, ElMessageBox } from 'element-plus'
import api from '@/api/client'
import PageHeader from '@/components/PageHeader.vue'
import AppCard from '@/components/AppCard.vue'

const { t } = useI18n()

interface Rule {
  id: number
  priority: number
  rule_type: string
  payload: string
  target: string
  enabled: boolean
}

interface CountryStat {
  code: string
  name: string
  count: number
}

interface MatchResult {
  matched: boolean
  host: string
  port?: string
  rule_line: string
  rule_type: string
  payload: string
  target: string
  target_label: string
  source: string
  priority: number
  note?: string
}

const manualRules = ref<Rule[]>([])
const mergedRules = ref<{ rule: string; source: string; priority: number }[]>([])
const countries = ref<CountryStat[]>([])
const loadingManual = ref(false)
const loadingMerged = ref(false)
const mergedTotal = ref(0)
const defaultPolicy = ref('DIRECT')
const mergedPage = ref(1)
const mergedPageSize = 50
const dialogVisible = ref(false)
const saving = ref(false)
const targetMode = ref<'policy' | 'country'>('country')
const form = ref({ rule_type: 'DOMAIN-SUFFIX', payload: '', target: 'country:HK', priority: 100 })

const testURL = ref('')
const testing = ref(false)
const testResult = ref<MatchResult | null>(null)

const importVisible = ref(false)
const importMode = ref<'append' | 'replace'>('append')
const importText = ref('')
const importing = ref(false)
const exportLoading = ref(false)

const countryTargets = computed(() =>
  countries.value.map(c => ({
    value: `country:${c.code}`,
    label: t('rules.countryFastest', { name: c.name }),
  })),
)

const policyTargets = computed(() => [
  { value: 'DIRECT', label: t('rules.targetDirect') },
  { value: 'REJECT', label: t('rules.targetReject') },
  { value: 'PROXY', label: t('rules.targetProxy') },
  { value: 'GLOBAL', label: t('rules.targetGlobal') },
])

const currentTargetOptions = computed(() =>
  targetMode.value === 'country' ? countryTargets.value : policyTargets.value,
)

watch(targetMode, (mode) => {
  if (mode === 'country') {
    const first = countries.value[0]
    form.value.target = first ? `country:${first.code}` : 'country:HK'
  } else {
    form.value.target = 'PROXY'
  }
})

async function loadManual() {
  loadingManual.value = true
  try {
    const { data } = await api.get('/rules?source=manual')
    manualRules.value = data.items || []
  } finally {
    loadingManual.value = false
  }
}

async function loadCountries() {
  const { data } = await api.get('/countries')
  countries.value = data.items || []
}

async function loadMerged() {
  loadingMerged.value = true
  try {
    const { data } = await api.get('/rules/merged', {
      params: {
        limit: mergedPageSize,
        offset: (mergedPage.value - 1) * mergedPageSize,
      },
    })
    mergedRules.value = data.items || []
    mergedTotal.value = data.total || 0
    defaultPolicy.value = data.default_policy || 'DIRECT'
  } finally {
    loadingMerged.value = false
  }
}

function onMergedPageChange(page: number) {
  mergedPage.value = page
  loadMerged()
}

async function load() {
  await loadManual()
  void loadCountries()
  void loadMerged()
}

function targetLabel(target: string) {
  if (target.startsWith('country:')) {
    const code = target.slice(8)
    const hit = countries.value.find(c => c.code === code)
    return hit ? t('rules.countryFastest', { name: hit.name }) : target
  }
  return target
}

function openCreate() {
  targetMode.value = countries.value.length ? 'country' : 'policy'
  form.value = {
    rule_type: 'DOMAIN-SUFFIX',
    payload: '',
    target: countries.value[0] ? `country:${countries.value[0].code}` : 'PROXY',
    priority: 100,
  }
  dialogVisible.value = true
}

async function save() {
  saving.value = true
  try {
    await api.post('/rules', form.value)
    ElMessage.success(t('rules.ruleAdded'))
    dialogVisible.value = false
    load()
  } finally {
    saving.value = false
  }
}

async function remove(row: Rule) {
  await ElMessageBox.confirm(t('rules.confirmDelete'), t('common.confirm'))
  await api.delete(`/rules/${row.id}`)
  load()
}

async function runTest() {
  const url = testURL.value.trim()
  if (!url) {
    ElMessage.warning(t('rules.urlRequired'))
    return
  }
  testing.value = true
  testResult.value = null
  try {
    const { data } = await api.post('/rules/test', { url })
    testResult.value = data
  } finally {
    testing.value = false
  }
}

function downloadBlob(data: Blob, filename: string) {
  const url = URL.createObjectURL(data)
  const a = document.createElement('a')
  a.href = url
  a.download = filename
  a.click()
  URL.revokeObjectURL(url)
}

async function exportRules(format: 'json' | 'text') {
  exportLoading.value = true
  try {
    const { data } = await api.get('/rules/export', {
      params: { format: format === 'text' ? 'text' : 'json' },
      responseType: 'blob',
    })
    downloadBlob(data, `prism-rules.${format === 'text' ? 'txt' : 'json'}`)
    ElMessage.success(t('rules.exported'))
  } finally {
    exportLoading.value = false
  }
}

function openImport() {
  importMode.value = 'append'
  importText.value = ''
  importVisible.value = true
}

function onImportFileChange(uploadFile: { raw?: File }) {
  const raw = uploadFile.raw
  if (!raw) return
  const reader = new FileReader()
  reader.onload = () => {
    importText.value = String(reader.result || '')
  }
  reader.readAsText(raw)
}

async function submitImport() {
  const text = importText.value.trim()
  if (!text) {
    ElMessage.warning(t('rules.pasteRequired'))
    return
  }
  if (importMode.value === 'replace') {
    await ElMessageBox.confirm(t('rules.importConfirmReplace'), t('common.confirm'), {
      type: 'warning',
    })
  }
  importing.value = true
  try {
    const { data } = await api.post('/rules/import', {
      mode: importMode.value,
      text,
    })
    const errs: string[] = data.errors || []
    if (errs.length) {
      ElMessage.warning(t('rules.importedPartial', { n: data.imported, s: data.skipped }))
    } else {
      ElMessage.success(t('rules.imported', { n: data.imported }))
    }
    importVisible.value = false
    load()
  } catch (e: unknown) {
    const err = e as { response?: { data?: { error?: string; errors?: string[] } } }
    const detail = err.response?.data?.errors?.join('；') || err.response?.data?.error
    ElMessage.error(detail || t('rules.importFailed'))
  } finally {
    importing.value = false
  }
}

onMounted(load)
</script>

<template>
  <div class="page">
    <PageHeader :title="t('rules.title')" :description="t('rules.desc')">
      <template #actions>
        <el-button @click="load">{{ t('common.refresh') }}</el-button>
        <el-dropdown trigger="click" @command="(cmd: 'json' | 'text') => exportRules(cmd)">
          <el-button :loading="exportLoading">
            {{ t('common.export') }}
          </el-button>
          <template #dropdown>
            <el-dropdown-menu>
              <el-dropdown-item command="json">{{ t('rules.exportJson') }}</el-dropdown-item>
              <el-dropdown-item command="text">{{ t('rules.exportText') }}</el-dropdown-item>
            </el-dropdown-menu>
          </template>
        </el-dropdown>
        <el-button @click="openImport">{{ t('common.import') }}</el-button>
        <el-button type="primary" @click="openCreate">{{ t('rules.addDialogTitle') }}</el-button>
      </template>
    </PageHeader>

    <AppCard :title="t('rules.testCard')">
      <div class="card-toolbar">
        <el-input
          v-model="testURL"
          :placeholder="t('rules.testPlaceholder')"
          clearable
          class="toolbar-input--grow"
          @keyup.enter="runTest"
        />
        <el-button type="primary" :loading="testing" @click="runTest">{{ t('rules.test') }}</el-button>
      </div>
      <div v-if="testResult" class="card-inset-block test-result">
        <p><span class="label">{{ t('rules.parsedHost') }}</span>{{ testResult.host }}<span v-if="testResult.port">:{{ testResult.port }}</span></p>
        <p><span class="label">{{ t('rules.matchedRule') }}</span><code class="inline-code">{{ testResult.rule_line }}</code></p>
        <p><span class="label">{{ t('rules.outboundTarget') }}</span>{{ testResult.target_label || testResult.target }}</p>
        <p><span class="label">{{ t('common.source') }}</span>{{ testResult.source }} · {{ t('rules.priority') }} {{ testResult.priority }}</p>
        <p v-if="testResult.note" class="form-hint form-hint--flush">{{ testResult.note }}</p>
      </div>
      <p v-else class="form-hint form-hint--flush card-footer-hint">{{ t('rules.testHint') }}</p>
    </AppCard>

    <div class="content-grid content-grid--2">
      <AppCard :title="t('rules.manualRules')">
        <el-table :data="manualRules" v-loading="loadingManual" size="small">
          <el-table-column prop="priority" :label="t('rules.priority')" width="80" />
          <el-table-column prop="rule_type" :label="t('common.type')" width="120" />
          <el-table-column prop="payload" :label="t('rules.match')" min-width="120" />
          <el-table-column :label="t('rules.target')" width="140">
            <template #default="{ row }">
              {{ targetLabel(row.target) }}
            </template>
          </el-table-column>
          <el-table-column :label="t('common.actions')" width="80" fixed="right">
            <template #default="{ row }">
              <el-button size="small" type="danger" link @click="remove(row)">{{ t('common.delete') }}</el-button>
            </template>
          </el-table-column>
        </el-table>
      </AppCard>
      <AppCard :title="t('rules.mergedPreview')">
        <div class="card-toolbar card-toolbar--desc">
          <p class="form-hint form-hint--flush">{{ t('rules.mergedSummary', { total: mergedTotal, policy: targetLabel(defaultPolicy) }) }}</p>
        </div>
        <el-table :data="mergedRules" v-loading="loadingMerged" size="small" class="table-scroll--md">
          <el-table-column :label="t('rules.seq')" width="70">
            <template #default="{ $index }">
              {{ (mergedPage - 1) * mergedPageSize + $index + 1 }}
            </template>
          </el-table-column>
          <el-table-column prop="priority" :label="t('rules.priority')" width="80" />
          <el-table-column prop="rule" :label="t('rules.rule')" min-width="200" show-overflow-tooltip />
          <el-table-column prop="source" :label="t('common.source')" width="90" />
        </el-table>
        <div class="card-pager">
          <el-pagination
            v-model:current-page="mergedPage"
            :page-size="mergedPageSize"
            :total="mergedTotal"
            layout="total, prev, pager, next, jumper"
            @current-change="onMergedPageChange"
          />
        </div>
      </AppCard>
    </div>

    <el-dialog v-model="importVisible" :title="t('rules.importTitle')" width="560px" destroy-on-close>
      <el-form label-width="100px">
        <el-form-item :label="t('rules.importMode')">
          <el-radio-group v-model="importMode">
            <el-radio value="append">{{ t('rules.append') }}</el-radio>
            <el-radio value="replace">{{ t('rules.replace') }}</el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item :label="t('rules.importFile')">
          <el-upload
            :auto-upload="false"
            :show-file-list="false"
            accept=".txt,.json,.yaml,.yml"
            :on-change="onImportFileChange"
          >
            <el-button>{{ t('rules.chooseFile') }}</el-button>
          </el-upload>
          <p class="form-hint">{{ t('rules.importFileHint') }}</p>
        </el-form-item>
        <el-form-item :label="t('rules.importContent')">
          <el-input
            v-model="importText"
            type="textarea"
            :rows="10"
            :placeholder="t('rules.importPlaceholder')"
          />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="importVisible = false">{{ t('common.cancel') }}</el-button>
        <el-button type="primary" :loading="importing" @click="submitImport">{{ t('common.import') }}</el-button>
      </template>
    </el-dialog>

    <el-dialog v-model="dialogVisible" :title="t('rules.addDialogTitle')" width="520px" destroy-on-close>
      <el-form label-width="100px">
        <el-form-item :label="t('common.type')">
          <el-select v-model="form.rule_type" class="w-full">
            <el-option label="DOMAIN" value="DOMAIN" />
            <el-option label="DOMAIN-SUFFIX" value="DOMAIN-SUFFIX" />
            <el-option label="DOMAIN-KEYWORD" value="DOMAIN-KEYWORD" />
            <el-option label="IP-CIDR" value="IP-CIDR" />
          </el-select>
        </el-form-item>
        <el-form-item :label="t('rules.matchValue')">
          <el-input v-model="form.payload" :placeholder="t('rules.matchPlaceholder')" />
        </el-form-item>
        <el-form-item :label="t('rules.outboundType')">
          <el-radio-group v-model="targetMode">
            <el-radio value="country">{{ t('rules.byCountry') }}</el-radio>
            <el-radio value="policy">{{ t('rules.byPolicy') }}</el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item :label="t('rules.outboundTargetLabel')">
          <el-select
            :key="targetMode"
            v-model="form.target"
            filterable
            class="w-full"
            :placeholder="targetMode === 'country' ? t('rules.selectCountryPool') : t('rules.selectPolicy')"
          >
            <el-option
              v-for="opt in currentTargetOptions"
              :key="opt.value"
              :label="opt.label"
              :value="opt.value"
            />
          </el-select>
          <p class="form-hint">{{ t('rules.countryPoolHint') }}</p>
        </el-form-item>
        <el-form-item :label="t('rules.priority')">
          <el-input-number v-model="form.priority" :min="1" :max="9999" />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="dialogVisible = false">{{ t('common.cancel') }}</el-button>
        <el-button type="primary" :loading="saving" @click="save">{{ t('common.confirm') }}</el-button>
      </template>
    </el-dialog>
  </div>
</template>
