from db import get_connection


def create_match_clock_table() -> None:
    query = """
    CREATE TABLE IF NOT EXISTS match_clocks (
        match_id BIGINT PRIMARY KEY REFERENCES matches(id) ON DELETE CASCADE,
        current_period VARCHAR(10) NOT NULL DEFAULT '1H',
        timer_running BOOLEAN NOT NULL DEFAULT FALSE,
        accumulated_seconds INTEGER NOT NULL DEFAULT 0,
        period_started_at TIMESTAMP NULL,
        updated_at TIMESTAMP NOT NULL DEFAULT NOW()
    );
    """

    conn = get_connection()
    try:
        with conn.cursor() as cur:
            cur.execute(query)
        conn.commit()
    finally:
        conn.close()


def ensure_match_clock(match_id: int) -> None:
    query = """
    INSERT INTO match_clocks (match_id, current_period, timer_running, accumulated_seconds, period_started_at, updated_at)
    VALUES (%s, '1H', FALSE, 0, NULL, NOW())
    ON CONFLICT (match_id) DO NOTHING;
    """

    conn = get_connection()
    try:
        with conn.cursor() as cur:
            cur.execute(query, (match_id,))
        conn.commit()
    finally:
        conn.close()


def get_match_clock(match_id: int) -> dict:
    ensure_match_clock(match_id)

    query = """
    SELECT
        match_id,
        current_period,
        timer_running,
        accumulated_seconds,
        period_started_at,
        CASE
            WHEN timer_running = TRUE AND period_started_at IS NOT NULL
                THEN accumulated_seconds + FLOOR(EXTRACT(EPOCH FROM (NOW() - period_started_at)))::INT
            ELSE accumulated_seconds
        END AS current_seconds
    FROM match_clocks
    WHERE match_id = %s;
    """

    conn = get_connection()
    try:
        with conn.cursor() as cur:
            cur.execute(query, (match_id,))
            row = cur.fetchone()
    finally:
        conn.close()

    return {
        "match_id": row[0],
        "current_period": row[1],
        "timer_running": bool(row[2]),
        "accumulated_seconds": row[3] or 0,
        "period_started_at": row[4].isoformat() if row[4] else None,
        "current_seconds": row[5] or 0,
    }


def update_match_clock(match_id: int, action: str, seconds: int | None = None) -> dict:
    ensure_match_clock(match_id)

    conn = get_connection()
    try:
        with conn.cursor() as cur:
            if action == "start_1h":
                cur.execute(
                    """
                    UPDATE match_clocks
                    SET current_period = '1H', timer_running = TRUE, accumulated_seconds = 0,
                        period_started_at = NOW(), updated_at = NOW()
                    WHERE match_id = %s;
                    """,
                    (match_id,),
                )
            elif action == "pause":
                cur.execute(
                    """
                    UPDATE match_clocks
                    SET accumulated_seconds = CASE
                            WHEN timer_running = TRUE AND period_started_at IS NOT NULL
                                THEN accumulated_seconds + FLOOR(EXTRACT(EPOCH FROM (NOW() - period_started_at)))::INT
                            ELSE accumulated_seconds
                        END,
                        timer_running = FALSE,
                        period_started_at = NULL,
                        updated_at = NOW()
                    WHERE match_id = %s;
                    """,
                    (match_id,),
                )
            elif action == "halftime":
                cur.execute(
                    """
                    UPDATE match_clocks
                    SET accumulated_seconds = CASE
                            WHEN timer_running = TRUE AND period_started_at IS NOT NULL
                                THEN accumulated_seconds + FLOOR(EXTRACT(EPOCH FROM (NOW() - period_started_at)))::INT
                            ELSE accumulated_seconds
                        END,
                        current_period = 'HT',
                        timer_running = FALSE,
                        period_started_at = NULL,
                        updated_at = NOW()
                    WHERE match_id = %s;
                    """,
                    (match_id,),
                )
            elif action == "start_2h":
                cur.execute(
                    """
                    UPDATE match_clocks
                    SET current_period = '2H', timer_running = TRUE,
                        accumulated_seconds = CASE WHEN accumulated_seconds < 2700 THEN 2700 ELSE accumulated_seconds END,
                        period_started_at = NOW(),
                        updated_at = NOW()
                    WHERE match_id = %s;
                    """,
                    (match_id,),
                )
            elif action == "finish":
                cur.execute(
                    """
                    UPDATE match_clocks
                    SET accumulated_seconds = CASE
                            WHEN timer_running = TRUE AND period_started_at IS NOT NULL
                                THEN accumulated_seconds + FLOOR(EXTRACT(EPOCH FROM (NOW() - period_started_at)))::INT
                            ELSE accumulated_seconds
                        END,
                        current_period = 'FT',
                        timer_running = FALSE,
                        period_started_at = NULL,
                        updated_at = NOW()
                    WHERE match_id = %s;
                    """,
                    (match_id,),
                )
            elif action == "set_time":
                if seconds is None or not isinstance(seconds, int) or seconds < 0:
                    raise ValueError("invalid_seconds")
                cur.execute(
                    """
                    UPDATE match_clocks
                    SET accumulated_seconds = %s,
                        period_started_at = CASE WHEN timer_running THEN NOW() ELSE NULL END,
                        updated_at = NOW()
                    WHERE match_id = %s;
                    """,
                    (seconds, match_id),
                )
            else:
                raise ValueError("invalid_clock_action")
        conn.commit()
    except Exception:
        conn.rollback()
        raise
    finally:
        conn.close()

    return get_match_clock(match_id)
