import express from 'express';
import cors from 'cors';
import helmet from 'helmet';
import morgan from 'morgan';
import dotenv from 'dotenv';
import jwt from 'jsonwebtoken';
import pkg from 'pg';

dotenv.config();
const { Pool } = pkg;

const PORT = process.env.PORT || 8080;
const DATABASE_URL = process.env.DATABASE_URL || 'postgres://supersunday:supersunday@db:5432/supersunday';
const JWT_SECRET = process.env.JWT_SECRET || 'dev_secret';
const ADMIN_EMAIL = process.env.ADMIN_EMAIL || 'admin@supersunday.local';
const ADMIN_PASSWORD = process.env.ADMIN_PASSWORD || 'admin123';

const app = express();
app.use(helmet());
app.use(cors({ origin: process.env.CORS_ORIGIN?.split(',') || '*' }));
app.use(express.json({ limit: '2mb' }));
app.use(morgan('tiny'));

const pool = new Pool({ connectionString: DATABASE_URL });
async function q(text, params=[]) { const { rows } = await pool.query(text, params); return rows; }

function auth(req, res, next) {
  const header = req.headers.authorization || '';
  const token = header.startsWith('Bearer ') ? header.slice(7) : null;
  if (!token) return res.status(401).json({ error: 'missing token' });
  try { req.user = jwt.verify(token, JWT_SECRET); next(); }
  catch { res.status(401).json({ error: 'invalid token' }); }
}

/* Health + Auth */
app.get('/api/health', async (req, res) => {
  try { const { rows } = await pool.query('SELECT 1 as ok'); res.json({ status: 'ok', db: rows[0].ok === 1 }); }
  catch (e) { res.status(500).json({ status: 'error', error: String(e) }); }
});
app.post('/api/auth/login', (req, res) => {
  const { email, password } = req.body || {};
  if (email === ADMIN_EMAIL && password === ADMIN_PASSWORD) {
    const token = jwt.sign({ email, role: 'admin' }, JWT_SECRET, { expiresIn: '12h' });
    return res.json({ token });
  }
  res.status(401).json({ error: 'invalid credentials' });
});

/* Players */
app.get('/api/players', async (req, res) => {
  res.json(await q('SELECT * FROM players ORDER BY id DESC'));
});
app.get('/api/players/:id', async (req, res) => {
  const rows = await q('SELECT * FROM players WHERE id=$1', [+req.params.id]);
  if (!rows[0]) return res.status(404).json({ error: 'not found' });
  res.json(rows[0]);
});
app.post('/api/players', auth, async (req, res) => {
  const { first_name, last_name, email=null, ranking=0 } = req.body||{};
  if (!first_name || !last_name) return res.status(400).json({ error: 'first_name & last_name required' });
  const rows = await q('INSERT INTO players(first_name,last_name,email,ranking) VALUES ($1,$2,$3,$4) RETURNING *',
    [first_name, last_name, email, ranking]);
  res.status(201).json(rows[0]);
});
app.put('/api/players/:id', auth, async (req, res) => {
  const { first_name, last_name, email, ranking } = req.body||{};
  const rows = await q('UPDATE players SET first_name=$1,last_name=$2,email=$3,ranking=$4 WHERE id=$5 RETURNING *',
    [first_name, last_name, email, ranking, +req.params.id]);
  res.json(rows[0]);
});
app.delete('/api/players/:id', auth, async (req, res) => {
  await q('DELETE FROM players WHERE id=$1', [+req.params.id]); res.json({ ok: true });
});

/* Tournaments */
app.get('/api/tournaments', async (req, res) => {
  res.json(await q('SELECT * FROM tournaments ORDER BY start_date DESC, id DESC'));
});
app.get('/api/tournaments/upcoming', async (req, res) => {
  res.json(await q('SELECT * FROM tournaments WHERE start_date >= CURRENT_DATE ORDER BY start_date ASC LIMIT 10'));
});
app.get('/api/tournaments/:id', async (req, res) => {
  const id = +req.params.id;
  const [t] = await q('SELECT * FROM tournaments WHERE id=$1', [id]);
  if (!t) return res.status(404).json({ error: 'tournament not found' });
  const [{ enrollment_count }] = await q('SELECT COUNT(*)::int AS enrollment_count FROM enrollments WHERE tournament_id=$1', [id]);
  const [{ team_count }] = await q('SELECT COUNT(*)::int AS team_count FROM teams WHERE tournament_id=$1', [id]);
  const [{ match_count }] = await q('SELECT COUNT(*)::int AS match_count FROM matches WHERE tournament_id=$1', [id]);
  const nextRows = await q(`SELECT * FROM matches WHERE tournament_id=$1 AND status IN ('scheduled','playing') AND scheduled_at IS NOT NULL ORDER BY scheduled_at ASC LIMIT 1`, [id]);
  res.json({ ...t, enrollment_count, team_count, match_count, next_match: nextRows[0] || null });
});
app.get('/api/tournaments/:id/summary', async (req, res) => {
  const id = +req.params.id;
  const [t] = await q('SELECT * FROM tournaments WHERE id=$1', [id]);
  if (!t) return res.status(404).json({ error: 'tournament not found' });
  const enroll = await q(`
    SELECT p.id, p.first_name, p.last_name, p.ranking
    FROM enrollments e JOIN players p ON p.id=e.player_id
    WHERE e.tournament_id=$1 ORDER BY p.ranking ASC NULLS LAST, p.last_name ASC
  `, [id]);
  const matches = await q('SELECT * FROM matches WHERE tournament_id=$1 ORDER BY scheduled_at NULLS LAST, id ASC', [id]);
  res.json({ tournament: t, enrollments: enroll, matches });
});
app.post('/api/tournaments', auth, async (req, res) => {
  const { name, location=null, start_date, end_date } = req.body||{};
  if (!name || !start_date || !end_date) return res.status(400).json({ error: 'name, start_date, end_date required' });
  const rows = await q('INSERT INTO tournaments(name,location,start_date,end_date) VALUES ($1,$2,$3,$4) RETURNING *',
    [name, location, start_date, end_date]);
  res.status(201).json(rows[0]);
});
app.put('/api/tournaments/:id', auth, async (req, res) => {
  const { name, location, start_date, end_date } = req.body||{};
  const rows = await q('UPDATE tournaments SET name=$1,location=$2,start_date=$3,end_date=$4 WHERE id=$5 RETURNING *',
    [name, location, start_date, end_date, +req.params.id]);
  res.json(rows[0]);
});
app.delete('/api/tournaments/:id', auth, async (req, res) => {
  await q('DELETE FROM tournaments WHERE id=$1', [+req.params.id]); res.json({ ok: true });
});

/* Enrollments */
app.get('/api/enrollments', async (req, res) => {
  const tid = req.query.tournament_id ? +req.query.tournament_id : null;
  if (tid) {
    return res.json(await q(`
      SELECT e.player_id, p.first_name, p.last_name, p.ranking
      FROM enrollments e JOIN players p ON p.id=e.player_id
      WHERE e.tournament_id=$1 ORDER BY p.ranking ASC, p.last_name ASC
    `, [tid]));
  }
  res.json(await q('SELECT * FROM enrollments ORDER BY tournament_id, player_id'));
});
app.post('/api/enrollments', auth, async (req, res) => {
  const { player_id, tournament_id } = req.body||{};
  if (!player_id || !tournament_id) return res.status(400).json({ error: 'player_id & tournament_id required' });
  await q('INSERT INTO enrollments(player_id,tournament_id) VALUES($1,$2) ON CONFLICT DO NOTHING', [player_id, tournament_id]);
  res.status(201).json({ ok: true });
});
app.post('/api/enrollments/bulk', auth, async (req, res) => {
  const { player_ids = [], tournament_id } = req.body||{};
  if (!tournament_id || !Array.isArray(player_ids)) return res.status(400).json({ error: 'player_ids[] & tournament_id required' });
  for (const pid of player_ids) { await q('INSERT INTO enrollments(player_id,tournament_id) VALUES($1,$2) ON CONFLICT DO NOTHING', [pid, tournament_id]); }
  res.json({ ok: true, count: player_ids.length });
});
app.delete('/api/enrollments', auth, async (req, res) => {
  const { player_id, tournament_id } = req.body||{};
  await q('DELETE FROM enrollments WHERE player_id=$1 AND tournament_id=$2', [player_id, tournament_id]);
  res.json({ ok: true });
});

/* Teams */
app.get('/api/teams', async (req, res) => {
  const tid = req.query.tournament_id ? +req.query.tournament_id : null;
  if (tid) {
    return res.json(await q(`
      SELECT t.*,
             p1.first_name AS p1_first, p1.last_name AS p1_last,
             p2.first_name AS p2_first, p2.last_name AS p2_last
      FROM teams t
      JOIN players p1 ON p1.id=t.player1_id
      JOIN players p2 ON p2.id=t.player2_id
      WHERE t.tournament_id=$1 ORDER BY t.id DESC
    `, [tid]));
  }
  res.json(await q('SELECT * FROM teams ORDER BY id DESC'));
});
app.get('/api/teams/:id', async (req, res) => {
  const rows = await q('SELECT * FROM teams WHERE id=$1', [+req.params.id]);
  if (!rows[0]) return res.status(404).json({ error: 'not found' });
  res.json(rows[0]);
});
app.post('/api/teams', auth, async (req, res) => {
  const { player1_id, player2_id, tournament_id=null } = req.body||{};
  if (!player1_id || !player2_id) return res.status(400).json({ error: 'player1_id & player2_id required' });
  const rows = await q('INSERT INTO teams(player1_id,player2_id,tournament_id) VALUES ($1,$2,$3) RETURNING *',
    [Math.min(player1_id, player2_id), Math.max(player1_id, player2_id), tournament_id]);
  res.status(201).json(rows[0]);
});
app.post('/api/teams/auto', auth, async (req, res) => {
  const { tournament_id } = req.body||{};
  if (!tournament_id) return res.status(400).json({ error: 'tournament_id required' });
  const players = await q(`
    SELECT p.* FROM enrollments e JOIN players p ON p.id=e.player_id
    WHERE e.tournament_id=$1 ORDER BY p.ranking ASC NULLS LAST
  `, [tournament_id]);
  const created = [];
  for (let i=0;i<players.length;i+=2) {
    if (i+1 >= players.length) break;
    const a = players[i].id, b = players[i+1].id;
    const { rows } = await pool.query(
      'INSERT INTO teams(player1_id,player2_id,tournament_id) VALUES ($1,$2,$3) ON CONFLICT DO NOTHING RETURNING *',
      [Math.min(a,b), Math.max(a,b), tournament_id]
    );
    if (rows[0]) created.push(rows[0]);
  }
  res.json({ created_count: created.length, created });
});
app.put('/api/teams/:id', auth, async (req, res) => {
  const { player1_id, player2_id, tournament_id } = req.body||{};
  const rows = await q('UPDATE teams SET player1_id=$1,player2_id=$2,tournament_id=$3 WHERE id=$4 RETURNING *',
    [Math.min(player1_id, player2_id), Math.max(player1_id, player2_id), tournament_id, +req.params.id]);
  res.json(rows[0]);
});
app.delete('/api/teams/:id', auth, async (req, res) => {
  await q('DELETE FROM teams WHERE id=$1', [+req.params.id]); res.json({ ok: true });
});

/* Matches */
app.get('/api/matches', async (req, res) => {
  const tid = req.query.tournament_id ? +req.query.tournament_id : null;
  if (tid) return res.json(await q('SELECT * FROM matches WHERE tournament_id=$1 ORDER BY scheduled_at NULLS LAST, id DESC', [tid]));
  res.json(await q('SELECT * FROM matches ORDER BY scheduled_at NULLS LAST, id DESC'));
});
app.get('/api/matches/:id', async (req, res) => {
  const rows = await q('SELECT * FROM matches WHERE id=$1', [+req.params.id]);
  if (!rows[0]) return res.status(404).json({ error: 'not found' });
  res.json(rows[0]);
});
app.post('/api/matches', auth, async (req, res) => {
  const { tournament_id, court=null, round=null, scheduled_at=null, team_a_id=null, team_b_id=null } = req.body||{};
  if (!tournament_id) return res.status(400).json({ error: 'tournament_id required' });
  const rows = await q('INSERT INTO matches(tournament_id,court,round,scheduled_at,team_a_id,team_b_id) VALUES ($1,$2,$3,$4,$5,$6) RETURNING *',
    [tournament_id, court, round, scheduled_at, team_a_id, team_b_id]);
  res.status(201).json(rows[0]);
});
app.put('/api/matches/:id', auth, async (req, res) => {
  const { court, round, scheduled_at, team_a_id, team_b_id, status } = req.body||{};
  const rows = await q('UPDATE matches SET court=$1, round=$2, scheduled_at=$3, team_a_id=$4, team_b_id=$5, status=$6 WHERE id=$7 RETURNING *',
    [court, round, scheduled_at, team_a_id, team_b_id, status, +req.params.id]);
  res.json(rows[0]);
});
app.post('/api/matches/:id/score', auth, async (req, res) => {
  const { score_a, score_b, status='finished' } = req.body||{};
  const rows = await q('UPDATE matches SET score_a=$1, score_b=$2, status=$3 WHERE id=$4 RETURNING *',
    [score_a, score_b, status, +req.params.id]);
  res.json(rows[0]);
});
app.post('/api/matches/generate', auth, async (req, res) => {
  const { tournament_id, courts=['Court 1'], start_at=null, interval_minutes=20 } = req.body||{};
  if (!tournament_id) return res.status(400).json({ error: 'tournament_id required' });
  const teams = await q('SELECT id FROM teams WHERE tournament_id=$1 ORDER BY id ASC', [tournament_id]);
  if (teams.length < 2) return res.status(400).json({ error: 'not enough teams' });
  const now = start_at ? new Date(start_at) : new Date(Date.now() + 5*60*1000);
  let t = new Date(now); let courtIdx = 0; const created = [];
  for (let i=0;i<teams.length;i+=2) {
    if (i+1 >= teams.length) break;
    const a = teams[i].id, b = teams[i+1].id;
    const court = courts[courtIdx % courts.length]; courtIdx++;
    const { rows } = await pool.query(
      'INSERT INTO matches(tournament_id, court, round, scheduled_at, team_a_id, team_b_id, status) VALUES ($1,$2,$3,$4,$5,$6,$7) RETURNING *',
      [tournament_id, court, 'Americano', t.toISOString(), a, b, 'scheduled']
    );
    created.push(rows[0]); t = new Date(t.getTime() + interval_minutes*60*1000);
  }
  res.json({ created });
});

/* Leaderboard (simple): sums wins/losses by team in a tournament */
app.get('/api/leaderboard', async (req, res) => {
  const tid = req.query.tournament_id ? +req.query.tournament_id : null;
  if (!tid) return res.status(400).json({ error: 'tournament_id required' });
  const rows = await q(`
    SELECT team_id, SUM(w) AS wins, SUM(l) AS losses
    FROM (
      SELECT team_a_id AS team_id, CASE WHEN score_a>score_b THEN 1 ELSE 0 END AS w, CASE WHEN score_a<score_b THEN 1 ELSE 0 END AS l
      FROM matches WHERE tournament_id=$1 AND status='finished' AND team_a_id IS NOT NULL AND team_b_id IS NOT NULL
      UNION ALL
      SELECT team_b_id AS team_id, CASE WHEN score_b>score_a THEN 1 ELSE 0 END AS w, CASE WHEN score_b<score_a THEN 1 ELSE 0 END AS l
      FROM matches WHERE tournament_id=$1 AND status='finished' AND team_a_id IS NOT NULL AND team_b_id IS NOT NULL
    ) x
    GROUP BY team_id
    ORDER BY wins DESC, losses ASC
  `, [tid]);
  res.json(rows);
});

app.listen(PORT, () => console.log(`API listening on :${PORT}`));