-- Core business logic functions

CREATE OR REPLACE FUNCTION get_default_rules()
RETURNS JSONB AS $$
  SELECT jsonb_build_object(
    'points_win', 3,
    'points_draw', 1,
    'round_robin_format', 'double',
    'transfer_policy', 'anytime',
    'auto_qualify_count', 1,
    'strict_availability', false,
    'result_approval_required', true,
    'cup_format', jsonb_build_object(
      'legs', 'single',
      'third_place_match', false,
      'seeding', 'random'
    )
  );
$$ LANGUAGE sql IMMUTABLE;

-- Snapshot rules when activating competition
CREATE OR REPLACE FUNCTION activate_competition(p_competition_id UUID)
RETURNS VOID AS $$
DECLARE
  v_league_id UUID;
  v_latest_rules JSONB;
  v_version INT;
BEGIN
  SELECT league_id INTO v_league_id FROM competitions WHERE id = p_competition_id;

  SELECT rules, version INTO v_latest_rules, v_version
  FROM league_rules
  WHERE league_id = v_league_id
  ORDER BY version DESC
  LIMIT 1;

  IF v_latest_rules IS NULL THEN
    v_latest_rules := get_default_rules();
    v_version := 1;
  END IF;

  UPDATE competitions
  SET status = 'active',
      rules_snapshot = v_latest_rules,
      rule_set_version = v_version
  WHERE id = p_competition_id AND status = 'draft';
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

-- Generate double round-robin fixtures
CREATE OR REPLACE FUNCTION generate_league_fixtures(p_competition_id UUID)
RETURNS INT AS $$
DECLARE
  team_ids UUID[];
  n INT;
  rounds INT;
  r INT;
  i INT;
  j INT;
  fixed UUID;
  rotating UUID[];
  match_count INT := 0;
  leg INT;
BEGIN
  SELECT ARRAY_AGG(id ORDER BY name) INTO team_ids
  FROM teams WHERE competition_id = p_competition_id;

  n := COALESCE(array_length(team_ids, 1), 0);
  IF n < 2 THEN
    RAISE EXCEPTION 'Need at least 2 teams';
  END IF;

  DELETE FROM matches WHERE competition_id = p_competition_id AND status = 'scheduled';

  IF n % 2 = 1 THEN
    team_ids := team_ids || NULL::UUID;
    n := n + 1;
  END IF;

  rounds := n - 1;
  rotating := team_ids[2:n];

  FOR leg IN 1..2 LOOP
    FOR r IN 1..rounds LOOP
      IF team_ids[1] IS NOT NULL AND rotating[1] IS NOT NULL THEN
        IF leg = 1 THEN
          INSERT INTO matches (competition_id, home_team_id, away_team_id, round, matchday, leg, status)
          VALUES (p_competition_id, team_ids[1], rotating[1], r, r + (leg-1)*rounds, leg, 'scheduled');
        ELSE
          INSERT INTO matches (competition_id, home_team_id, away_team_id, round, matchday, leg, status)
          VALUES (p_competition_id, rotating[1], team_ids[1], r, r + (leg-1)*rounds, leg, 'scheduled');
        END IF;
        match_count := match_count + 1;
      END IF;

      FOR i IN 1..(array_length(rotating, 1) / 2) LOOP
        j := array_length(rotating, 1) - i + 1;
        IF rotating[i] IS NOT NULL AND rotating[j] IS NOT NULL AND i <> j THEN
          IF leg = 1 THEN
            INSERT INTO matches (competition_id, home_team_id, away_team_id, round, matchday, leg, status)
            VALUES (p_competition_id, rotating[i], rotating[j], r, r + (leg-1)*rounds, leg, 'scheduled');
          ELSE
            INSERT INTO matches (competition_id, home_team_id, away_team_id, round, matchday, leg, status)
            VALUES (p_competition_id, rotating[j], rotating[i], r, r + (leg-1)*rounds, leg, 'scheduled');
          END IF;
          match_count := match_count + 1;
        END IF;
      END LOOP;

      fixed := rotating[array_length(rotating, 1)];
      rotating := ARRAY[fixed] || rotating[1:array_length(rotating,1)-1];
    END LOOP;
  END LOOP;

  RETURN match_count;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

-- Generate cup bracket (single elimination, first round)
CREATE OR REPLACE FUNCTION generate_cup_bracket(p_competition_id UUID)
RETURNS INT AS $$
DECLARE
  team_ids UUID[];
  n INT;
  i INT;
  match_count INT := 0;
BEGIN
  SELECT ARRAY_AGG(id ORDER BY COALESCE(cup_seed, 999), name) INTO team_ids
  FROM teams WHERE competition_id = p_competition_id;

  n := COALESCE(array_length(team_ids, 1), 0);
  IF n < 2 THEN RAISE EXCEPTION 'Need at least 2 teams'; END IF;

  DELETE FROM matches WHERE competition_id = p_competition_id AND status = 'scheduled';

  i := 1;
  WHILE i < n LOOP
  IF team_ids[i] IS NOT NULL AND team_ids[i+1] IS NOT NULL THEN
    INSERT INTO matches (competition_id, home_team_id, away_team_id, bracket_round, bracket_slot, status)
    VALUES (p_competition_id, team_ids[i], team_ids[i+1], 1, (i+1)/2, 'scheduled');
    match_count := match_count + 1;
  END IF;
    i := i + 2;
  END LOOP;

  RETURN match_count;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

-- Submit match result from team
CREATE OR REPLACE FUNCTION submit_match_result(
  p_match_id UUID,
  p_team_id UUID,
  p_home_score INT,
  p_away_score INT
)
RETURNS VOID AS $$
DECLARE
  v_competition_id UUID;
  v_sub_count INT;
  v_home_sub INT;
  v_away_sub INT;
  v_sub1_home INT;
  v_sub1_away INT;
  v_sub2_home INT;
  v_sub2_away INT;
BEGIN
  SELECT competition_id INTO v_competition_id FROM matches WHERE id = p_match_id;

  INSERT INTO match_result_submissions (match_id, team_id, home_score, away_score, submitted_by)
  VALUES (p_match_id, p_team_id, p_home_score, p_away_score, auth.uid())
  ON CONFLICT (match_id, team_id) DO UPDATE
  SET home_score = EXCLUDED.home_score, away_score = EXCLUDED.away_score,
      submitted_at = now(), submitted_by = auth.uid();

  SELECT COUNT(*) INTO v_sub_count FROM match_result_submissions WHERE match_id = p_match_id;

  IF v_sub_count < 2 THEN
    UPDATE matches SET result_status = 'result_submitted', status = 'awaiting_results'
    WHERE id = p_match_id;
    RETURN;
  END IF;

  SELECT home_score, away_score INTO v_sub1_home, v_sub1_away
  FROM match_result_submissions WHERE match_id = p_match_id
  ORDER BY submitted_at LIMIT 1;

  SELECT home_score, away_score INTO v_sub2_home, v_sub2_away
  FROM match_result_submissions WHERE match_id = p_match_id
  ORDER BY submitted_at DESC LIMIT 1;

  IF v_sub1_home = v_sub2_home AND v_sub1_away = v_sub2_away THEN
    UPDATE matches SET result_status = 'pending_approval', status = 'pending_approval'
    WHERE id = p_match_id;
  ELSE
    UPDATE matches SET result_status = 'disputed', status = 'disputed'
    WHERE id = p_match_id;
  END IF;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

-- League manager approves result
CREATE OR REPLACE FUNCTION approve_match_result(p_match_id UUID)
RETURNS VOID AS $$
DECLARE
  v_sub RECORD;
BEGIN
  IF NOT EXISTS (
    SELECT 1 FROM matches m
    WHERE m.id = p_match_id
    AND is_competition_league_manager(m.competition_id)
  ) AND NOT EXISTS (
    SELECT 1 FROM matches m JOIN competitions c ON c.id = m.competition_id
    JOIN leagues l ON l.id = c.league_id
    WHERE m.id = p_match_id AND l.created_by = auth.uid()
  ) THEN
    RAISE EXCEPTION 'Not authorized';
  END IF;

  SELECT home_score, away_score INTO v_sub
  FROM match_result_submissions WHERE match_id = p_match_id LIMIT 1;

  UPDATE matches SET
    home_score = v_sub.home_score,
    away_score = v_sub.away_score,
    status = 'completed',
    result_status = 'completed',
    approved_by = auth.uid(),
    approved_at = now()
  WHERE id = p_match_id;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

-- League manager sets result directly
CREATE OR REPLACE FUNCTION set_match_result_by_manager(
  p_match_id UUID,
  p_home_score INT,
  p_away_score INT,
  p_note TEXT DEFAULT NULL
)
RETURNS VOID AS $$
BEGIN
  IF NOT EXISTS (
    SELECT 1 FROM matches m WHERE m.id = p_match_id
    AND is_competition_league_manager(m.competition_id)
  ) AND NOT EXISTS (
    SELECT 1 FROM matches m JOIN competitions c ON c.id = m.competition_id
    JOIN leagues l ON l.id = c.league_id
    WHERE m.id = p_match_id AND l.created_by = auth.uid()
  ) THEN
    RAISE EXCEPTION 'Not authorized';
  END IF;

  UPDATE matches SET
    home_score = p_home_score,
    away_score = p_away_score,
    status = 'completed',
    result_status = 'completed',
    approved_by = auth.uid(),
    approved_at = now(),
    resolution_note = p_note
  WHERE id = p_match_id;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

-- Sign schedule
CREATE OR REPLACE FUNCTION sign_match_schedule(p_match_id UUID, p_team_id UUID)
RETURNS VOID AS $$
DECLARE
  v_sig_count INT;
  v_proposed TIMESTAMPTZ;
BEGIN
  SELECT proposed_scheduled_at INTO v_proposed FROM matches WHERE id = p_match_id;

  INSERT INTO match_signatures (match_id, team_id, user_id, signature_type)
  VALUES (p_match_id, p_team_id, auth.uid(), 'schedule')
  ON CONFLICT (match_id, team_id, signature_type) DO NOTHING;

  SELECT COUNT(*) INTO v_sig_count FROM match_signatures
  WHERE match_id = p_match_id AND signature_type = 'schedule';

  IF v_sig_count >= 2 AND v_proposed IS NOT NULL THEN
    UPDATE matches SET
      status = 'schedule_confirmed',
      scheduled_at = v_proposed,
      venue = (SELECT home_stadium_name FROM teams t
               JOIN matches m ON m.home_team_id = t.id WHERE m.id = p_match_id)
    WHERE id = p_match_id;
  END IF;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

-- Propose schedule time
CREATE OR REPLACE FUNCTION propose_match_schedule(p_match_id UUID, p_scheduled_at TIMESTAMPTZ)
RETURNS VOID AS $$
BEGIN
  UPDATE matches SET
    proposed_scheduled_at = p_scheduled_at,
    status = 'schedule_pending'
  WHERE id = p_match_id;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
