"""Unit tests for the canonical warehouse."""

import json
import sqlite3

import pytest

from byteb4rb1e.homeostat.warehouse.canonical import (
    CanonicalWarehouse,
)
from byteb4rb1e.homeostat.warehouse.schema import (
    StepSnapshot,
    SleepSession,
    SleepStage,
    Meal,
    MealItem,
)


@pytest.fixture
def warehouse(tmp_path):
    return CanonicalWarehouse(root=tmp_path)


@pytest.fixture
def step():
    return StepSnapshot(
        source="fitbit",
        fetched_at="2026-03-19T15:00:00+00:00",
        date="2026-03-19",
        observed_at="2026-03-19T15:00:00+00:00",
        steps=8000,
    )


@pytest.fixture
def db():
    conn = sqlite3.connect(":memory:")
    yield conn
    conn.close()


class TestAppend:
    def test_creates_partition(self, warehouse, step):
        path = warehouse.append(
            "step-snapshot", step, "2026-03-19"
        )
        assert path.exists()
        assert path.name == "2026-03-19.jsonl"
        assert "step-snapshot" in str(path)

    def test_writes_valid_jsonl(self, warehouse, step):
        warehouse.append(
            "step-snapshot", step, "2026-03-19"
        )
        path = warehouse._partition_path(
            "step-snapshot", "2026-03-19"
        )
        row = json.loads(path.read_text().strip())
        assert row["steps"] == 8000
        assert row["source"] == "fitbit"


class TestAppendMany:
    def test_writes_multiple_records(self, warehouse, step):
        warehouse.append_many(
            "step-snapshot", [step, step], "2026-03-19"
        )
        path = warehouse._partition_path(
            "step-snapshot", "2026-03-19"
        )
        lines = path.read_text().strip().splitlines()
        assert len(lines) == 2

    def test_empty_list_returns_none(self, warehouse):
        result = warehouse.append_many(
            "step-snapshot", [], "2026-03-19"
        )
        assert result is None


class TestReadPartition:
    def test_reads_records(self, warehouse, step):
        warehouse.append(
            "step-snapshot", step, "2026-03-19"
        )
        records = warehouse.read_partition(
            "step-snapshot", "2026-03-19"
        )
        assert len(records) == 1
        assert records[0]["steps"] == 8000

    def test_missing_returns_empty(self, warehouse):
        assert warehouse.read_partition(
            "step-snapshot", "1999-01-01"
        ) == []


class TestIterPartitions:
    def test_yields_partitions(self, warehouse, step):
        warehouse.append(
            "step-snapshot", step, "2026-03-19"
        )
        partitions = list(warehouse.iter_partitions())
        assert len(partitions) == 1
        assert partitions[0][0] == "step-snapshot"
        assert partitions[0][1] == "2026-03-19"

    def test_filter_by_entity(self, warehouse, step):
        warehouse.append(
            "step-snapshot", step, "2026-03-19"
        )
        meal = Meal(
            source="fddb",
            fetched_at="2026-03-19T15:00:00+00:00",
            date="2026-03-19",
            meal_name="Breakfast",
            calories=500,
            protein_g=20.0,
            carbs_g=60.0,
            fat_g=15.0,
        )
        warehouse.append("meal", meal, "2026-03-19")
        partitions = list(
            warehouse.iter_partitions(
                entity_name="step-snapshot"
            )
        )
        assert len(partitions) == 1


class TestHydrate:
    def test_creates_tables_and_inserts(
        self, warehouse, step, db
    ):
        warehouse.append(
            "step-snapshot", step, "2026-03-19"
        )
        count = warehouse.hydrate(db)
        assert count == 1

        rows = db.execute(
            "SELECT steps FROM step_snapshot"
        ).fetchall()
        assert rows[0][0] == 8000

    def test_full_rebuild_clears_old(
        self, warehouse, step, db
    ):
        warehouse.append(
            "step-snapshot", step, "2026-03-19"
        )
        warehouse.hydrate(db)
        warehouse.hydrate(db)
        rows = db.execute(
            "SELECT COUNT(*) FROM step_snapshot"
        ).fetchone()
        assert rows[0] == 1

    def test_cross_reference_preserved(
        self, warehouse, db
    ):
        session = SleepSession(
            source="fitbit",
            fetched_at="2026-03-19T08:00:00+00:00",
            date="2026-03-19",
            bedtime="2026-03-18T23:00:00",
            wake_time="2026-03-19T07:00:00",
            duration_hours=8.0,
            score=90,
            is_main=True,
        )
        stage = SleepStage(
            source="fitbit",
            fetched_at="2026-03-19T08:00:00+00:00",
            date="2026-03-19",
            bedtime="2026-03-18T23:00:00",
            stage="deep",
            minutes=90,
        )
        warehouse.append(
            "sleep-session", session, "2026-03-19"
        )
        warehouse.append(
            "sleep-stage", stage, "2026-03-19"
        )
        warehouse.hydrate(db)

        rows = db.execute("""
            SELECT ss.duration_hours, st.stage, st.minutes
            FROM sleep_session ss
            JOIN sleep_stage st
              ON ss.date = st.date
             AND ss.bedtime = st.bedtime
        """).fetchall()
        assert len(rows) == 1
        assert rows[0] == (8.0, "deep", 90)
