import sqlite3
from contextlib import contextmanager
from pathlib import Path
from datetime import datetime, timezone

import config

INIT_SQL = """
CREATE TABLE IF NOT EXISTS sessions (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    started_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
    ended_at TEXT,
    notes TEXT
);

CREATE TABLE IF NOT EXISTS readings (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    session_id INTEGER NOT NULL,
    received_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
    device_id TEXT,
    mac TEXT,
    ble_connected INTEGER,
    battery INTEGER,
    unit TEXT,
    probe1_temp REAL,
    probe1_connected INTEGER,
    probe2_temp REAL,
    probe2_connected INTEGER,
    probe3_temp REAL,
    probe3_connected INTEGER,
    probe4_temp REAL,
    probe4_connected INTEGER,
    FOREIGN KEY (session_id) REFERENCES sessions(id)
);

CREATE TABLE IF NOT EXISTS setpoints (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    session_id INTEGER NOT NULL,
    probe_number INTEGER NOT NULL,
    label TEXT,
    target_temp REAL NOT NULL,
    created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
    FOREIGN KEY (session_id) REFERENCES sessions(id),
    UNIQUE(session_id, probe_number)
);

CREATE INDEX IF NOT EXISTS idx_readings_session_time
    ON readings(session_id, received_at);
"""


def init_db():
    Path(config.DATABASE_PATH).parent.mkdir(parents=True, exist_ok=True)
    with get_connection() as conn:
        conn.executescript(INIT_SQL)
        conn.commit()


@contextmanager
def get_connection():
    conn = sqlite3.connect(config.DATABASE_PATH)
    conn.row_factory = sqlite3.Row
    try:
        yield conn
    finally:
        conn.close()


def utc_now_iso():
    return datetime.now(timezone.utc).isoformat()


def create_session(name: str, notes: str = ""):
    with get_connection() as conn:
        cursor = conn.execute(
            "INSERT INTO sessions (name, notes) VALUES (?, ?)",
            (name, notes),
        )
        conn.commit()
        return cursor.lastrowid


def get_active_session():
    with get_connection() as conn:
        row = conn.execute(
            "SELECT * FROM sessions WHERE ended_at IS NULL ORDER BY started_at DESC LIMIT 1"
        ).fetchone()
        return dict(row) if row else None


def end_session(session_id: int):
    with get_connection() as conn:
        conn.execute(
            "UPDATE sessions SET ended_at = ? WHERE id = ?",
            (utc_now_iso(), session_id),
        )
        conn.commit()


def update_session_notes(session_id: int, notes: str):
    with get_connection() as conn:
        conn.execute(
            "UPDATE sessions SET notes = ? WHERE id = ?",
            (notes, session_id),
        )
        conn.commit()


def insert_reading(session_id: int, payload: dict):
    probes = payload.get("probes", [])
    temps = []
    connected = []
    for i in range(4):
        if i < len(probes) and probes[i].get("connected"):
            temps.append(probes[i].get("temperature"))
            connected.append(1)
        else:
            temps.append(None)
            connected.append(0)

    with get_connection() as conn:
        conn.execute(
            """
            INSERT INTO readings (
                session_id, received_at, device_id, mac, ble_connected, battery, unit,
                probe1_temp, probe1_connected,
                probe2_temp, probe2_connected,
                probe3_temp, probe3_connected,
                probe4_temp, probe4_connected
            ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
            """,
            (
                session_id,
                utc_now_iso(),
                payload.get("deviceId"),
                payload.get("mac"),
                1 if payload.get("connected") else 0,
                payload.get("battery"),
                payload.get("unit"),
                temps[0], connected[0],
                temps[1], connected[1],
                temps[2], connected[2],
                temps[3], connected[3],
            ),
        )
        conn.commit()


def get_latest_reading(session_id: int):
    with get_connection() as conn:
        row = conn.execute(
            "SELECT * FROM readings WHERE session_id = ? ORDER BY received_at DESC LIMIT 1",
            (session_id,),
        ).fetchone()
        return dict(row) if row else None


def get_readings(session_id: int, minutes: int = 60, probe_number: int = None):
    with get_connection() as conn:
        if probe_number is not None:
            column = f"probe{probe_number}_temp"
            rows = conn.execute(
                f"""
                SELECT received_at, {column} AS temp, probe{probe_number}_connected AS connected
                FROM readings
                WHERE session_id = ?
                  AND received_at > datetime('now', '-{minutes} minutes')
                  AND {column} IS NOT NULL
                ORDER BY received_at ASC
                """,
                (session_id,),
            ).fetchall()
        else:
            rows = conn.execute(
                f"""
                SELECT received_at,
                       probe1_temp, probe1_connected,
                       probe2_temp, probe2_connected,
                       probe3_temp, probe3_connected,
                       probe4_temp, probe4_connected
                FROM readings
                WHERE session_id = ?
                  AND received_at > datetime('now', '-{minutes} minutes')
                ORDER BY received_at ASC
                """,
                (session_id,),
            ).fetchall()
        return [dict(row) for row in rows]


def set_setpoint(session_id: int, probe_number: int, label: str, target_temp: float):
    with get_connection() as conn:
        conn.execute(
            """
            INSERT INTO setpoints (session_id, probe_number, label, target_temp)
            VALUES (?, ?, ?, ?)
            ON CONFLICT(session_id, probe_number) DO UPDATE SET
                label = excluded.label,
                target_temp = excluded.target_temp,
                created_at = excluded.created_at
            """,
            (session_id, probe_number, label, target_temp),
        )
        conn.commit()


def get_setpoints(session_id: int):
    with get_connection() as conn:
        rows = conn.execute(
            "SELECT * FROM setpoints WHERE session_id = ? ORDER BY probe_number",
            (session_id,),
        ).fetchall()
        return [dict(row) for row in rows]
