import { promises as fs } from 'fs'
import { getServerDataPath, getProjectPath } from './paths.js'
import { getSpieljahrForDate } from './spielplan-import.js'
import { parseDelimitedLine } from './spielplan-data.js'

const OUTPUT_DIR = getServerDataPath('spielplan-import')
const DEFAULT_ASSOCIATION = 'HeTTV'

function normalizeHeaderName(value) {
  return String(value || '').trim().toLowerCase()
}

function toUrlOrNull(value) {
  const raw = String(value || '').trim()
  if (!raw) return null

  try {
    return new URL(raw)
  } catch {
    return null
  }
}

function isSupportedTableUrl(urlValue) {
  const parsed = toUrlOrNull(urlValue)
  if (!parsed) return false

  const host = parsed.hostname.toLowerCase()
  if (host !== 'www.mytischtennis.de' && host !== 'mytischtennis.de' && host !== 'click-tt.de' && host !== 'www.click-tt.de') {
    return false
  }

  return parsed.pathname.includes('/tabelle/')
}

async function fileExists(filePath) {
  try {
    await fs.access(filePath)
    return true
  } catch {
    return false
  }
}

function extractRemixContext(html) {
  const marker = 'window.__remixContext = '
  const start = html.indexOf(marker)
  if (start === -1) {
    throw new Error('window.__remixContext nicht gefunden')
  }

  const jsonStart = start + marker.length
  let depth = 0
  let inString = false
  let escaped = false

  for (let i = jsonStart; i < html.length; i += 1) {
    const char = html[i]

    if (inString) {
      if (escaped) {
        escaped = false
      } else if (char === '\\') {
        escaped = true
      } else if (char === '"') {
        inString = false
      }
      continue
    }

    if (char === '"') {
      inString = true
    } else if (char === '{') {
      depth += 1
    } else if (char === '}') {
      depth -= 1
      if (depth === 0) {
        return JSON.parse(html.slice(jsonStart, i + 1))
      }
    }
  }

  throw new Error('Ende von window.__remixContext nicht gefunden')
}

function getTableRoutePayload(loaderData) {
  const exactKey = 'routes/click-tt+/$association+/$season+/$type+/$groupname.gruppe.$urlid+/tabelle.$filter'
  if (loaderData?.[exactKey]) {
    return { routeKey: exactKey, payload: loaderData[exactKey] }
  }

  const fallbackKey = Object.keys(loaderData || {}).find((key) => key.includes('/tabelle.$filter'))
  if (fallbackKey && loaderData[fallbackKey]) {
    return { routeKey: fallbackKey, payload: loaderData[fallbackKey] }
  }

  throw new Error('Tabellen-Route in loaderData nicht gefunden')
}

function normalizeTableData(url, routeKey, payload) {
  const data = payload?.data || {}
  if (!Array.isArray(data.league_table)) {
    throw new Error('Ungueltige Tabellenstruktur: league_table fehlt')
  }

  const leagueTable = data.league_table

  return {
    url,
    routeKey,
    fetchedAt: new Date().toISOString(),
    association: payload?.association || null,
    season: payload?.season || null,
    groupname: payload?.groupname || null,
    urlid: payload?.urlid || null,
    filter: payload?.filter || null,
    headInfos: Array.isArray(data.head_infos) ? data.head_infos : [],
    setCount: data.set_count ?? null,
    gameCount: data.game_count ?? null,
    noMeetings: data.no_meetings ?? null,
    gamesPerSet: data.games_per_set ?? null,
    leagueTtrAvg: data.league_ttr_avg ?? null,
    subTableInfo: data.sub_table_info ?? null,
    rowCount: leagueTable.length,
    leagueTable
  }
}

function extractSeasonSlugFromUrl(url) {
  const match = String(url || '').match(/\/click-tt\/[^/]+\/(\d{2}--\d{2})\//)
  return match?.[1] || null
}

function sanitizeSeasonSlug(value) {
  const seasonSlug = String(value || '').trim()
  return /^\d{2}--\d{2}$/.test(seasonSlug) ? seasonSlug : null
}

async function resolveMannschaftenCsvPath() {
  const candidates = [
    getServerDataPath('public-data', 'mannschaften.csv'),
    getServerDataPath('mannschaften.csv'),
    getProjectPath('.output', 'public', 'data', 'mannschaften.csv'),
    getProjectPath('public', 'data', 'mannschaften.csv')
  ]

  for (const candidate of candidates) {
    if (await fileExists(candidate)) return candidate
  }

  throw new Error('Mannschaften-Datei nicht gefunden')
}

function extractRowsWithTableUrl(csvContent) {
  const lines = csvContent.split(/\r?\n/).filter((line) => line.trim() !== '')
  if (lines.length < 2) return []

  const headers = parseDelimitedLine(lines[0], ',').map(normalizeHeaderName)
  const teamIdx = headers.indexOf('mannschaft')
  const leagueIdx = headers.indexOf('liga')
  const infoLinkIdx = headers.indexOf('weitere informationen link')

  if (infoLinkIdx === -1) {
    throw new Error('CSV-Spalte weitere_informationen_link nicht gefunden')
  }

  const rows = []

  for (const line of lines.slice(1)) {
    const values = parseDelimitedLine(line, ',')
    const tableUrl = values[infoLinkIdx] ? String(values[infoLinkIdx]).trim() : ''
    if (!tableUrl) continue
    if (!isSupportedTableUrl(tableUrl)) continue

    rows.push({
      teamName: teamIdx >= 0 ? (values[teamIdx] || null) : null,
      leagueName: leagueIdx >= 0 ? (values[leagueIdx] || null) : null,
      tableUrl
    })
  }

  return rows
}

async function fetchTable(url) {
  const response = await fetch(url, {
    headers: {
      accept: 'text/html,application/xhtml+xml',
      'accept-language': 'de-DE,de;q=0.9'
    }
  })

  if (!response.ok) {
    throw new Error(`Tabellen-Download fehlgeschlagen: HTTP ${response.status}`)
  }

  const html = await response.text()
  const context = extractRemixContext(html)
  const loaderData = context?.state?.loaderData || {}
  const { routeKey, payload } = getTableRoutePayload(loaderData)
  return normalizeTableData(url, routeKey, payload)
}

export async function importLeagueTables(options = {}) {
  const today = options.today ?? new Date()
  const season = getSpieljahrForDate(today)
  const csvPath = await resolveMannschaftenCsvPath()
  const csvContent = await fs.readFile(csvPath, 'utf8')
  const teams = extractRowsWithTableUrl(csvContent)

  const entries = []
  const errors = []

  for (const team of teams) {
    try {
      const table = await fetchTable(team.tableUrl)
      entries.push({
        teamName: team.teamName,
        leagueName: team.leagueName,
        table
      })
    } catch (error) {
      errors.push({
        teamName: team.teamName,
        leagueName: team.leagueName,
        tableUrl: team.tableUrl,
        error: error?.message || String(error)
      })
    }
  }

  const fallbackSeasonSlug = teams.length > 0 ? extractSeasonSlugFromUrl(teams[0].tableUrl) : null
  const seasonSlug = sanitizeSeasonSlug(fallbackSeasonSlug) || sanitizeSeasonSlug(season.seasonSlug) || getSpieljahrForDate(today).seasonSlug
  const outputFile = `${OUTPUT_DIR}/tables_${seasonSlug}.json`

  const payload = {
    format: 'harheimertc.tables.v1',
    importedAt: new Date().toISOString(),
    source: {
      association: DEFAULT_ASSOCIATION,
      season: {
        seasonSlug,
        dateStart: season.dateStart,
        dateEnd: season.dateEnd
      },
      csvPath
    },
    teamCount: teams.length,
    importedCount: entries.length,
    errorCount: errors.length,
    tables: entries,
    errors
  }

  await fs.mkdir(OUTPUT_DIR, { recursive: true })
  await fs.writeFile(outputFile, `${JSON.stringify(payload, null, 2)}\n`, 'utf8')

  return {
    outputFile,
    seasonSlug,
    teamCount: teams.length,
    importedCount: entries.length,
    errorCount: errors.length,
    tables: entries,
    errors
  }
}