from __future__ import annotations

import argparse
import gzip
import hashlib
import json
import sqlite3
import tempfile
import unittest
from pathlib import Path

from dataset_schema import (
    OSM_ATTRIBUTION,
    OSM_LICENSE,
    OSM_LICENSE_URL,
    ROAD_CLASS_CODES,
    SCHEMA_VERSION,
    SPEED_SOURCE_OSM_EXPLICIT,
    create_schema,
    encode_geometry,
    insert_segment,
)
from publish_dataset import publish


class PublishDatasetTest(unittest.TestCase):
    def test_bundled_mobile_catalog_never_references_geofabrik_or_raw_pbf(self) -> None:
        repository = Path(__file__).resolve().parents[2]
        catalog_path = repository / "core/data/src/main/assets/offline/regions.json"
        payload = catalog_path.read_text(encoding="utf-8")

        self.assertNotIn("download.geofabrik.de", payload)
        self.assertNotIn(".osm.pbf", payload)

    def test_publish_creates_manifest_catalog_diff_and_report(self) -> None:
        with tempfile.TemporaryDirectory() as directory:
            root = Path(directory)
            previous = root / "previous.sqlite"
            current = root / "current.sqlite"
            output = root / "published"
            _dataset(previous, "old", "90")
            _dataset(current, "new", "70")

            publish(
                argparse.Namespace(
                    dataset=current,
                    output=output,
                    version="2026.08.09",
                    region_name="Île-de-France",
                    base_url="https://road-data.example.test/",
                    previous=previous,
                    previous_version="2026.08.01",
                    compression="gzip",
                    compare_compression=False,
                )
            )

            road_data = output / "v1" / "road-data"
            manifest = json.loads((road_data / "regions" / "FR-IDF" / "manifest.json").read_text())
            catalog = json.loads((road_data / "catalog.json").read_text())
            self.assertEqual("2026.08.09", manifest["version"])
            self.assertEqual(64, len(manifest["checksumSha256"]))
            package = road_data / "packages" / "FR-IDF-2026.08.09.sqlite.gz"
            self.assertEqual(package.stat().st_size, manifest["sizeBytes"])
            self.assertEqual(current.stat().st_size, manifest["installedSizeBytes"])
            self.assertEqual(_sha256(package), manifest["checksumSha256"])
            with gzip.open(package, "rb") as stream:
                self.assertEqual(current.read_bytes(), stream.read())
            self.assertEqual("2026.08.01", manifest["diffs"][0]["fromVersion"])
            self.assertTrue(manifest["diffs"][0]["packageUrl"].endswith(".sqlite.gz"))
            self.assertEqual("FR-IDF", catalog["regions"][0]["id"])
            self.assertNotIn("download.geofabrik.de", json.dumps(catalog))
            self.assertTrue((road_data / "reports" / "FR-IDF-2026.08.09.json").is_file())

    def test_geofabrik_cannot_be_used_as_mobile_publication_endpoint(self) -> None:
        with tempfile.TemporaryDirectory() as directory:
            root = Path(directory)
            dataset = root / "current.sqlite"
            _dataset(dataset, "new", "70")

            with self.assertRaisesRegex(ValueError, "import source"):
                publish(
                    argparse.Namespace(
                        dataset=dataset,
                        output=root / "published",
                        version="2026.08.09",
                        region_name="Île-de-France",
                        base_url="https://download.geofabrik.de/europe/france/",
                        previous=None,
                        previous_version=None,
                        compression="gzip",
                        compare_compression=False,
                    )
                )


def _dataset(path: Path, dataset_id: str, maxspeed: str) -> None:
    connection = sqlite3.connect(path)
    create_schema(connection)
    points = ((48.0, 2.0), (48.0, 2.001))
    insert_segment(
        connection,
        {
            "segment_id": "segment-1",
            "osm_way_id": 1,
            "from_node_id": 1,
            "to_node_id": 2,
            "direction": 1,
            "length_meters": 100.0,
            "geometry": encode_geometry(points),
            "road_class": ROAD_CLASS_CODES["primary"],
            "speed_limit_kmh": int(maxspeed),
            "speed_source": SPEED_SOURCE_OSM_EXPLICIT,
            "speed_confidence": 99,
            "road_flags": 1,
            "road_name": "Fixture",
            "points": points,
        },
    )
    connection.execute(
        "INSERT INTO dataset_metadata VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
        (
            SCHEMA_VERSION,
            dataset_id,
            "FR",
            "FR-IDF",
            "fixture.osm.pbf",
            "2026-08-09T00:00:00Z",
            "2026-08-09T00:00:00Z",
            480000000,
            480000000,
            20000000,
            20010000,
            1,
            OSM_ATTRIBUTION,
            OSM_LICENSE,
            OSM_LICENSE_URL,
        ),
    )
    connection.commit()
    connection.close()


def _sha256(path: Path) -> str:
    return hashlib.sha256(path.read_bytes()).hexdigest()


if __name__ == "__main__":
    unittest.main()
