import { normalizeResponseData, requestJson } from "./request"

const JSY_API_BASE = import.meta.env.VITE_JSY_API_BASE || "/jsyApi"
const OPEN_API_BASE = import.meta.env.VITE_OPEN_API_BASE || "/openApi"
const CURRENT_YEAR = new Date().getFullYear()

function joinBase(base, path) {
  if (/^https?:\/\//.test(path)) return path
  return `${base}${path.startsWith("/") ? path : `/${path}`}`
}

function unwrapResponse(response) {
  const failed =
    response?.success === false &&
    response?.code !== undefined &&
    ![0, 200, "0", "200"].includes(response.code)

  if (failed) {
    throw new Error(response?.msg || response?.message || "接口请求失败")
  }

  return normalizeResponseData(response)
}

function get(base, path, params, options = {}) {
  return requestJson(joinBase(base, path), {
    params,
    timeout: options.timeout || 18000,
  }).then(unwrapResponse)
}

function post(base, path, body, options = {}) {
  return requestJson(joinBase(base, path), {
    method: "POST",
    body: body ? JSON.stringify(body) : undefined,
    timeout: options.timeout || 18000,
    headers: {
      "Content-Type": "application/x-www-form-urlencoded",
      accept: "*/*",
    },
  }).then(unwrapResponse)
}

export function getYakDistribution() {
  return get(JSY_API_BASE, "/api/yak/distribution").then((data) => normalizeRows(data))
}

export function getYakStructure() {
  return get(JSY_API_BASE, "/api/yak/structure").then((data) => normalizeRows(data))
}

export function getYakForecast() {
  return get(JSY_API_BASE, "/api/yak/forecast").then((data) => normalizeRows(data))
}

export function getYakSlaughterOutput() {
  return post(JSY_API_BASE, "/api/yak/slaughterOutput").then((data) => normalizeRows(data))
}

export function getYakTradeOverview(year = CURRENT_YEAR) {
  const params = typeof year === "object" ? year : { year }
  return get(OPEN_API_BASE, "/yak/trade/overview", params).then((data) => data || {})
}

export function getYakTradeOptions() {
  return get(OPEN_API_BASE, "/yak/trade/options").then((data) => data || {})
}

export function getYakTradeRecords(params = {}) {
  return get(OPEN_API_BASE, "/yak/trade/records", params).then((data) => data || {})
}

export function getYakEpidemicAnalysis(params = {}) {
  return get(OPEN_API_BASE, "/yak/epidemic/analysis", params).then((data) => data || {})
}

export function getYakEpidemicRecords(params = {}) {
  return get(OPEN_API_BASE, "/yak/epidemic/records", params).then((data) => data || {})
}

export function getYakEpidemicStats(params = {}) {
  return get(OPEN_API_BASE, "/yak/epidemic/stats", params).then((data) => data || {})
}

export function getYakEpidemicVillageStats(params = {}) {
  return get(OPEN_API_BASE, "/yak/epidemic/village-stats", params).then((data) => data || {})
}

export function getYakEpidemicDetail(earTag) {
  return get(OPEN_API_BASE, "/yak/epidemic/detail", { earTag }).then((data) => data || null)
}

export async function getYakTownRows() {
  const rows = await getYakDistribution()
  return rows
    .map((item, index) => ({
      key: getValue(item, ["areaCode", "area_code", "code", "id"], `yak-town-${index}`),
      name: getValue(item, ["areaName", "area_name", "zoneName", "townName", "name"], `区域${index + 1}`),
      value: toNumber(getValue(item, ["number", "yakCount", "yak_count", "count", "value"])),
      unit: "头",
    }))
    .filter((row) => row.name && Number.isFinite(row.value))
    .sort((a, b) => b.value - a.value)
}

export async function getYakStructureRows() {
  const rows = await getYakStructure()
  const normalizedRows = rows
    .map((item, index) => {
      const sex = getValue(item, ["sex", "gender"], "")
      const sexName = normalizeSexName(sex)
      const ageRange = getValue(item, ["ageRange", "age_range", "age", "name", "type"], "")
      const name = [sexName, ageRange].filter(Boolean).join(" ") || `结构${index + 1}`
      return {
        key: getValue(item, ["id", "key"], `${name}-${index}`),
        name,
        value: toNumber(getValue(item, ["number", "count", "value"])),
        unit: "头",
      }
    })
    .filter((row) => row.name && Number.isFinite(row.value))

  return aggregateRows(normalizedRows)
}

export async function getYakForecastRows() {
  const rows = await getYakForecast()
  return rows
    .map((item, index) => {
      const month = getValue(item, ["month", "date", "name", "time"], `预测${index + 1}`)
      return {
        key: `${month}-${index}`,
        name: formatMonthName(month),
        value: toNumber(getValue(item, ["number", "count", "yakCount", "value"])),
        unit: "头",
        extra: formatExtraValue("增速", getValue(item, ["speed", "growth", "growthRate", "rate"])),
      }
    })
    .filter((row) => row.name && Number.isFinite(row.value))
}

export async function getYakStockRows() {
  const rows = await getYakSlaughterOutput()
  const latestByArea = getLatestRowsByName(rows)
  return latestByArea
    .map((item, index) => ({
      key: `${getValue(item, ["areaName", "area_name", "name"], `区域${index + 1}`)}-${index}`,
      name: getValue(item, ["areaName", "area_name", "name"], `区域${index + 1}`),
      value: toNumber(getValue(item, ["current", "stock", "stockCount", "yakCount", "number"])),
      unit: "头",
      extra: formatExtraValue("出栏", getValue(item, ["slaughterOutput", "slaughter_output", "output"])),
    }))
    .filter((row) => row.name && Number.isFinite(row.value))
    .sort((a, b) => b.value - a.value)
}

export async function getYakTradeRows() {
  const overview = await getYakTradeOverview()
  const usageRows = normalizeRows(overview.usageCounts || overview.usage_counts)
  const sourceRows = usageRows.length ? usageRows : normalizeRows(overview.startTownCounts || overview.start_town_counts)
  return sourceRows
    .map((item, index) => ({
      key: getValue(item, ["name", "label"], `trade-${index}`),
      name: getValue(item, ["name", "label"], `类型${index + 1}`),
      value: toNumber(getValue(item, ["headCount", "head_count", "amount", "value", "count"])),
      unit: "头",
      extra: formatExtraValue("记录", getValue(item, ["recordCount", "record_count"])),
    }))
    .filter((row) => row.name && Number.isFinite(row.value))
    .sort((a, b) => b.value - a.value)
}

function normalizeRows(data) {
  if (Array.isArray(data)) return data
  if (Array.isArray(data?.rows)) return data.rows
  if (Array.isArray(data?.list)) return data.list
  if (Array.isArray(data?.records)) return data.records
  if (Array.isArray(data?.data)) return data.data
  return []
}

function aggregateRows(rows = []) {
  const map = new Map()
  rows.forEach((row) => {
    const current = map.get(row.name) || { ...row, value: 0 }
    current.value += row.value
    map.set(row.name, current)
  })
  return [...map.values()].sort((a, b) => b.value - a.value)
}

function getLatestRowsByName(rows = []) {
  const sorted = rows.slice().sort((a, b) => String(getValue(a, ["month", "date", "time"], "")).localeCompare(String(getValue(b, ["month", "date", "time"], ""))))
  const map = new Map()
  sorted.forEach((row, index) => {
    const name = getValue(row, ["areaName", "area_name", "name"], `区域${index + 1}`)
    map.set(name, row)
  })
  return [...map.values()]
}

function getValue(source, keys, fallback = "") {
  for (const key of keys) {
    const value = source?.[key]
    if (value !== undefined && value !== null && value !== "") return value
  }
  return fallback
}

function normalizeSexName(value) {
  if (["boy", "male", "公", "公牛"].includes(value)) return "公牛"
  if (["girl", "female", "母", "母牛"].includes(value)) return "母牛"
  return value || ""
}

function formatMonthName(value) {
  const text = String(value || "")
  const monthMatch = text.match(/(?:^|\D)(1[0-2]|0?[1-9])(?:月|$|-)/)
  if (monthMatch) return `${Number(monthMatch[1])}月`
  return text
}

function formatExtraValue(label, value) {
  const number = toNumber(value)
  if (!Number.isFinite(number)) return ""
  return `${label}：${number.toLocaleString("zh-CN", { maximumFractionDigits: 2 })}`
}

function toNumber(value) {
  if (value === undefined || value === null || value === "") return NaN
  const number = Number(String(value).replace(/,/g, "").replace(/%/g, ""))
  return Number.isFinite(number) ? number : NaN
}
