import csv
import filecmp
from pathlib import Path

import pytest
from sqlalchemy import Engine

from kotobuki import update_usagi_file
from tests.python.mapping_updater.conftest import (
    MAP_TO_0_USAGI_FILE,
    USAGI_STCM_FILE,
    write_tmp_usagi_file,
)

pytestmark = pytest.mark.usefixtures("create_vocab_tables")


def test_inspect_only_does_not_change_file(tmp_path: Path, pg_db_engine: Engine):
    tmp_usagi_file = write_tmp_usagi_file(tmp_path, USAGI_STCM_FILE)
    assert len(list(tmp_path.glob("*"))) == 1
    update_usagi_file(pg_db_engine, "vocab", tmp_usagi_file, inspect_only=True)
    assert len(list(tmp_path.glob("*"))) == 1
    assert filecmp.cmp(USAGI_STCM_FILE, tmp_usagi_file)


def test_overwrite(tmp_path: Path, pg_db_engine: Engine):
    tmp_usagi_file = write_tmp_usagi_file(tmp_path, USAGI_STCM_FILE)
    update_usagi_file(pg_db_engine, "vocab", tmp_usagi_file, overwrite=True)
    with tmp_usagi_file.open("r", encoding="utf8") as f:
        reader = csv.DictReader(f)
        mappings = [(line["source_code"], line["target_concept_id"]) for line in reader]
    assert mappings == [
        ("X1", "3"),
        ("X2", "3"),
        ("X3", "3"),
        ("X4", "4"),
        ("X5", "5"),
        ("X6", "6"),
        ("X7", "8"),
        ("X7", "9"),
        ("X8", "8"),
        ("X9", "9"),
        ("X10", "11"),
        ("X10", "12"),
        ("X11", "11"),
        ("X12", "12"),
        ("X13", "14"),
        ("X13", "15"),
        ("X13", "16"),
        ("X14", "14"),
        ("X15", "15"),
        ("X16", "16"),
    ]


def test_homonyms(tmp_path: Path, pg_db_engine: Engine):
    tmp_usagi_file = write_tmp_usagi_file(tmp_path, USAGI_STCM_FILE)
    update_usagi_file(pg_db_engine, "vocab", tmp_usagi_file, overwrite=True, allow_homonyms=True)
    with tmp_usagi_file.open("r", encoding="utf8") as f:
        reader = csv.DictReader(f)
        mappings = [(line["source_code"], line["target_concept_id"]) for line in reader]
    assert mappings == [
        ("X1", "3"),
        ("X2", "3"),
        ("X3", "3"),
        ("X4", "4"),
        ("X5", "6"),  # Now mapped to 6 via a homonym
        ("X6", "6"),
        ("X7", "8"),
        ("X7", "9"),
        ("X8", "8"),
        ("X9", "9"),
        ("X10", "11"),
        ("X10", "12"),
        ("X11", "11"),
        ("X12", "12"),
        ("X13", "14"),
        ("X13", "15"),
        ("X13", "16"),
        ("X14", "14"),
        ("X15", "15"),
        ("X16", "16"),
    ]


def test_domain_id_only_updated_when_mapped_to_non_zero(tmp_path: Path, pg_db_engine: Engine):
    tmp_usagi_save_file = write_tmp_usagi_file(tmp_path, MAP_TO_0_USAGI_FILE)

    def get_mappings_from_file(usagi_file: Path) -> list[tuple[str, str]]:
        with usagi_file.open("r", encoding="utf8") as f:
            reader = csv.DictReader(f)
            return [(line["domainId"], line["conceptId"]) for line in reader]

    expected_original = [
        ("", "0"),
        ("BLA", "0"),
        ("", "0"),
        ("Observation", "17"),
        ("Drug", "18"),
    ]
    assert get_mappings_from_file(MAP_TO_0_USAGI_FILE) == expected_original

    # Without update_all, concept properties of existing mappings are not updated
    update_usagi_file(pg_db_engine, "vocab", tmp_usagi_save_file, overwrite=True, update_all=False)
    assert get_mappings_from_file(tmp_usagi_save_file) == expected_original

    # Codes that map to 0 will not be updated, but codes of which the
    # domain_id is outdated, will get an update
    update_usagi_file(pg_db_engine, "vocab", tmp_usagi_save_file, overwrite=True, update_all=True)
    assert get_mappings_from_file(tmp_usagi_save_file) == [
        ("", "0"),
        ("BLA", "0"),
        ("", "0"),
        ("Condition", "17"),
        ("Condition", "18"),
    ]
