from pathlib import Path
from types import SimpleNamespace

import pytest

from nemo_library_etl.adapter.migman.extract_from_file import MigManExtractFromFile


class DummyLogger:
    def info(self, *args, **kwargs):
        pass

    def debug(self, *args, **kwargs):
        pass

    def warning(self, *args, **kwargs):
        pass

    def error(self, *args, **kwargs):
        pass


class DummyLocalDatabase:
    def __init__(self):
        self.ingest_calls = []
        self.upload_calls = []

    def ingest_csv(self, **kwargs):
        self.ingest_calls.append(kwargs)

    def upload_table_to_nemo(self, **kwargs):
        self.upload_calls.append(kwargs)


def make_file_cfg(
    *,
    active=True,
    project="Customer Data",
    file_path="input.csv",
    separator=";",
    quote='"',
    dateformat="%d-%m-%Y",
    encoding="utf-8",
    header=True,
    columns=None,
    all_varchar=True,
):
    if columns is None:
        columns = ["A", "B"]

    return SimpleNamespace(
        active=active,
        project=project,
        file_path=file_path,
        separator=separator,
        quote=quote,
        dateformat=dateformat,
        encoding=encoding,
        header=header,
        columns=columns,
        all_varchar=all_varchar,
    )


def make_cfg(*, files, load_to_nemo=True, nemo_project_prefix="mme", delete_temp_files=True):
    return SimpleNamespace(
        extract=SimpleNamespace(
            file=files,
            load_to_nemo=load_to_nemo,
            nemo_project_prefix=nemo_project_prefix,
            delete_temp_files=delete_temp_files,
        )
    )


def build_extractor(cfg, local_database=None):
    if local_database is None:
        local_database = DummyLocalDatabase()

    return MigManExtractFromFile(
        nl=SimpleNamespace(),
        cfg=cfg,
        logger=DummyLogger(),
        fh=SimpleNamespace(),
        local_database=local_database,
    )


def test_extract_from_file_ingests_active_csv_and_uploads_to_nemo(tmp_path):
    csv_file = tmp_path / "customer_data.csv"
    csv_file.write_text("A;B\n1;2\n", encoding="utf-8")

    file_cfg = make_file_cfg(
        project="Customer Data",
        file_path=str(csv_file),
        columns=["A", "B"],
    )
    cfg = make_cfg(files=[file_cfg], load_to_nemo=True)
    db = DummyLocalDatabase()
    extractor = build_extractor(cfg, db)

    extractor.extract_from_file()

    assert len(db.ingest_calls) == 1
    ingest_call = db.ingest_calls[0]

    assert ingest_call["filename"] == csv_file.absolute().as_posix()
    assert ingest_call["table_name"] == "customer_data"
    assert ingest_call["separator"] == ";"
    assert ingest_call["quote"] == '"'
    assert ingest_call["dateformat"] == "%d-%m-%Y"
    assert ingest_call["encoding"] == "utf-8"
    assert ingest_call["header"] is True
    assert ingest_call["columns"] == ["A", "B"]
    assert ingest_call["all_varchar"] is True

    assert len(db.upload_calls) == 1
    upload_call = db.upload_calls[0]
    assert upload_call["table_name"] == "Customer Data"
    assert upload_call["project_name"] == "mmeCustomer Data"
    assert upload_call["delete_temp_files"] is True


def test_extract_from_file_skips_inactive_entries(tmp_path):
    active_file = tmp_path / "active.csv"
    active_file.write_text("A;B\n1;2\n", encoding="utf-8")

    inactive_file = tmp_path / "inactive.csv"
    inactive_file.write_text("A;B\n3;4\n", encoding="utf-8")

    cfg = make_cfg(
        files=[
            make_file_cfg(active=True, project="Active Project", file_path=str(active_file)),
            make_file_cfg(active=False, project="Inactive Project", file_path=str(inactive_file)),
        ],
        load_to_nemo=False,
    )

    db = DummyLocalDatabase()
    extractor = build_extractor(cfg, db)

    extractor.extract_from_file()

    assert len(db.ingest_calls) == 1
    assert db.ingest_calls[0]["table_name"] == "active_project"
    assert db.upload_calls == []


def test_extract_from_file_raises_for_missing_file():
    cfg = make_cfg(
        files=[
            make_file_cfg(
                active=True,
                project="Missing File",
                file_path="does_not_exist.csv",
            )
        ]
    )

    extractor = build_extractor(cfg)

    with pytest.raises(FileNotFoundError, match="File not found"):
        extractor.extract_from_file()


def test_extract_from_file_raises_for_unsupported_file_format(tmp_path):
    txt_file = tmp_path / "source.txt"
    txt_file.write_text("not,csv", encoding="utf-8")

    cfg = make_cfg(
        files=[
            make_file_cfg(
                active=True,
                project="Wrong Format",
                file_path=str(txt_file),
            )
        ]
    )

    extractor = build_extractor(cfg)

    with pytest.raises(ValueError, match="Unsupported file format"):
        extractor.extract_from_file()