import { useEffect, useState } from 'react'
import './App.css'

type Participant = {
  id: string
  name: string
  isPlaceholder: boolean
}

type Team = {
  id: number
  playerA: Participant
  playerB: Participant
}

type RoundResult = {
  id: number
  teams: Team[]
}

type SaveState = 'idle' | 'saving' | 'saved' | 'error'

const STORAGE_KEYS = {
  areaA: 'badminton-match-hub::area-a',
  areaB: 'badminton-match-hub::area-b',
} as const

const PLACEHOLDER_NAME = '那個'
const TOTAL_ROUNDS = 3

const defaultAreaA = ['建喵', '柏威', '景涵', 'Gary', '昱翔']
const defaultAreaB = ['小念', '玟瑄', 'RuRu', '肉肉', '蓉蓉']

function App() {
  const [areaAInput, setAreaAInput] = useState(() =>
    loadRoster(STORAGE_KEYS.areaA, defaultAreaA),
  )
  const [areaBInput, setAreaBInput] = useState(() =>
    loadRoster(STORAGE_KEYS.areaB, defaultAreaB),
  )
  const [targetDate, setTargetDate] = useState(() => formatDateInputValue())
  const [results, setResults] = useState<RoundResult[]>([])
  const [error, setError] = useState('')
  const [saveState, setSaveState] = useState<SaveState>('idle')
  const [saveMessage, setSaveMessage] = useState('')

  useEffect(() => {
    window.localStorage.setItem(STORAGE_KEYS.areaA, areaAInput)
  }, [areaAInput])

  useEffect(() => {
    window.localStorage.setItem(STORAGE_KEYS.areaB, areaBInput)
  }, [areaBInput])

  const parsedAreaA = parseRoster(areaAInput)
  const parsedAreaB = parseRoster(areaBInput)
  const teamCount = Math.max(parsedAreaA.length, parsedAreaB.length)
  const placeholderCountA = Math.max(0, teamCount - parsedAreaA.length)
  const placeholderCountB = Math.max(0, teamCount - parsedAreaB.length)

  function generateGroups() {
    if (parsedAreaA.length === 0 || parsedAreaB.length === 0) {
      setResults([])
      setError('A 區與 B 區都至少要輸入 1 位成員。')
      setSaveState('idle')
      setSaveMessage('')
      return
    }

    const prepared = prepareParticipants(parsedAreaA, parsedAreaB)
    const nextResults = Array.from({ length: TOTAL_ROUNDS }, (_, index) => ({
      id: index + 1,
      teams: createRoundTeams(prepared.areaA, prepared.areaB, index),
    }))

    setResults(nextResults)
    setError('')
    setSaveState('idle')
    setSaveMessage('已產生配對，請按「上傳資料」。')
  }

  async function uploadResults() {
    if (results.length === 0) {
      setSaveState('error')
      setSaveMessage('請先產生配對結果，再上傳資料。')
      return
    }

    if (!targetDate) {
      setSaveState('error')
      setSaveMessage('請先選擇目標日期。')
      return
    }

    setSaveState('saving')
    setSaveMessage('上傳資料到資料庫中...')

    try {
      await saveMatchResults(convertDateToKey(targetDate), parsedAreaA, parsedAreaB, results)
      setSaveState('saved')
      setSaveMessage(`已同步到資料庫：${convertDateToKey(targetDate)}`)
    } catch (saveError) {
      setSaveState('error')
      setSaveMessage(
        saveError instanceof Error ? saveError.message : '資料庫儲存失敗，請稍後再試。',
      )
    }
  }

  function resetDemo() {
    setAreaAInput(defaultAreaA.join('\n'))
    setAreaBInput(defaultAreaB.join('\n'))
    setResults([])
    setError('')
    setSaveState('idle')
    setSaveMessage('')
  }

  return (
    <main className="app-shell">
      <section className="hero-card">
        <div className="hero-copy">
          <p className="eyebrow">羽毛球隊伍配對</p>
          <h1>羽毛球分組配對器</h1>
          <p className="hero-text">
            輸入 A 區與 B 區名單後，系統會產生 3 組完整配對。
            每一隊都是 1 位 A 區成員搭配 1 位 B 區成員；
            若某一區人數不足，會自動補入「那個」。
          </p>
          <div className="hero-actions">
            <button className="primary-button" type="button" onClick={generateGroups}>
              產生三組配對
            </button>
            <button className="ghost-button" type="button" onClick={resetDemo}>
              載入範例名單
            </button>
          </div>
          {saveMessage ? (
            <p className={`save-status save-status-${saveState}`}>{saveMessage}</p>
          ) : null}
        </div>

        <div className="hero-stats">
          <article className="stat-card">
            <span>A 區人數</span>
            <strong>{parsedAreaA.length}</strong>
          </article>
          <article className="stat-card">
            <span>B 區人數</span>
            <strong>{parsedAreaB.length}</strong>
          </article>
          <article className="tip-card">
            <h2>摘要</h2>
            <p>
              每組共 {teamCount} 隊，A 區補位 {placeholderCountA} 人，B 區補位 {placeholderCountB} 人。
            </p>
          </article>
        </div>
      </section>

      <section className="panel input-panel">
        <div className="panel-heading">
          <p className="eyebrow">名單輸入</p>
          <h2>輸入 A 區與 B 區名單</h2>
        </div>

        <div className="upload-row">
          <label className="date-field">
            <span>目標日期</span>
            <input
              type="date"
              value={targetDate}
              onChange={(event) => setTargetDate(event.target.value)}
            />
          </label>
          <button
            className="primary-button upload-button"
            type="button"
            onClick={() => void uploadResults()}
            disabled={results.length === 0 || saveState === 'saving'}
          >
            上傳資料
          </button>
        </div>

        <div className="input-grid">
          <label className="roster-field">
            <span>A 區成員</span>
            <textarea
              value={areaAInput}
              onChange={(event) => setAreaAInput(event.target.value)}
              placeholder={'每行一位\n例如：建喵'}
              rows={10}
            />
          </label>

          <label className="roster-field">
            <span>B 區成員</span>
            <textarea
              value={areaBInput}
              onChange={(event) => setAreaBInput(event.target.value)}
              placeholder={'每行一位\n例如：小念'}
              rows={10}
            />
          </label>
        </div>

        <p className="helper-text">支援換行、逗號、頓號分隔，會自動去除重複名稱。</p>
        {error ? <p className="error-banner">{error}</p> : null}
      </section>

      <section className="panel results-panel">
        <div className="panel-heading">
          <p className="eyebrow">配對結果</p>
          <h2>三組名單</h2>
        </div>

        {results.length > 0 ? (
          <div className="round-list">
            {results.map((round) => (
              <article className="round-card" key={round.id}>
                <h3 className="round-title">第 {round.id} 組</h3>
                <div className="team-list">
                  {round.teams.map((team) => (
                    <article className="team-card" key={`${round.id}-${team.id}`}>
                      <span className="team-index">第 {team.id} 隊</span>
                      <div className="team-line">
                        <span className={team.playerA.isPlaceholder ? 'name-placeholder' : 'name-a'}>
                          {team.playerA.name}
                        </span>
                        <span className="team-divider">×</span>
                        <span className={team.playerB.isPlaceholder ? 'name-placeholder' : 'name-b'}>
                          {team.playerB.name}
                        </span>
                      </div>
                    </article>
                  ))}
                </div>
              </article>
            ))}
          </div>
        ) : (
          <div className="empty-state">
            <p>按下「產生三組配對」後，這裡會直接顯示誰跟誰一隊。</p>
          </div>
        )}
      </section>
    </main>
  )
}

function prepareParticipants(areaA: string[], areaB: string[]) {
  const targetCount = Math.max(areaA.length, areaB.length)
  const shuffledA = shuffleList(areaA)
  const shuffledB = shuffleList(areaB)

  return {
    areaA: createParticipants(shuffledA, targetCount, 'A'),
    areaB: createParticipants(shuffledB, targetCount, 'B'),
  }
}

function createParticipants(players: string[], targetCount: number, zone: 'A' | 'B') {
  const participants: Participant[] = players.map((name, index) => ({
    id: `${zone}-${index}-${name}`,
    name,
    isPlaceholder: false,
  }))

  for (let index = players.length; index < targetCount; index += 1) {
    participants.push({
      id: `${zone}-placeholder-${index}`,
      name: PLACEHOLDER_NAME,
      isPlaceholder: true,
    })
  }

  return participants
}

function createRoundTeams(areaA: Participant[], areaB: Participant[], roundIndex: number) {
  return areaA.map((playerA, index) => ({
    id: index + 1,
    playerA,
    playerB: areaB[(index + roundIndex) % areaB.length],
  }))
}

async function saveMatchResults(
  time: string,
  areaA: string[],
  areaB: string[],
  rounds: RoundResult[],
) {
  const response = await fetch('/api/match-results', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      time,
      areaA,
      areaB,
      teams: rounds.map((round) => ({
        round: round.id,
        teams: round.teams.map((team) => ({
          team: team.id,
          a: team.playerA.name,
          b: team.playerB.name,
        })),
      })),
    }),
  })

  const payload = (await response.json()) as { ok?: boolean; message?: string }

  if (!response.ok || !payload.ok) {
    throw new Error(payload.message ?? '資料庫儲存失敗。')
  }
}

function formatDateInputValue() {
  const now = new Date()
  const year = now.getFullYear()
  const month = String(now.getMonth() + 1).padStart(2, '0')
  const day = String(now.getDate()).padStart(2, '0')
  return `${year}-${month}-${day}`
}

function convertDateToKey(dateValue: string) {
  const [year = '', month = '', day = ''] = dateValue.split('-')
  return `${year}${month}${day}`
}

function loadRoster(storageKey: string, fallbackList: string[]) {
  const storedValue = window.localStorage.getItem(storageKey)
  return storedValue && storedValue.trim() ? storedValue : fallbackList.join('\n')
}

function parseRoster(input: string) {
  const uniqueNames = new Set<string>()

  input
    .split(/[\n,，、]+/g)
    .map((name) => name.trim())
    .filter(Boolean)
    .forEach((name) => uniqueNames.add(name))

  return Array.from(uniqueNames)
}

function shuffleList<T>(list: T[]) {
  const next = [...list]

  for (let index = next.length - 1; index > 0; index -= 1) {
    const swapIndex = Math.floor(Math.random() * (index + 1))
    ;[next[index], next[swapIndex]] = [next[swapIndex], next[index]]
  }

  return next
}

export default App
