from datetime import datetime, timedelta
from pathlib import Path

import pytest

from cg.constants import Pipeline
from cg.constants.constants import FileFormat
from cg.io.controller import ReadFile
from cg.meta.report.balsamic import BalsamicReportAPI
from cg.meta.report.mip_dna import MipDNAReportAPI
from cg.meta.report.rnafusion import RnafusionReportAPI
from cg.models.cg_config import CGConfig
from cg.store import Store
from cg.store.models import Case
from tests.apps.scout.conftest import MockScoutApi
from tests.mocks.balsamic_analysis_mock import MockBalsamicAnalysis
from tests.mocks.limsmock import MockLimsAPI
from tests.mocks.mip_analysis_mock import MockMipAnalysis
from tests.mocks.report import MockChanjo, MockHousekeeperMipDNAReportAPI


@pytest.fixture(scope="function")
def report_api_mip_dna(
    cg_context: CGConfig, lims_samples: list[dict], report_store: Store
) -> MipDNAReportAPI:
    """MIP DNA ReportAPI fixture."""
    cg_context.meta_apis["analysis_api"] = MockMipAnalysis(
        config=cg_context, pipeline=Pipeline.MIP_DNA
    )
    cg_context.status_db_ = report_store
    cg_context.lims_api_ = MockLimsAPI(cg_context, lims_samples)
    cg_context.chanjo_api_ = MockChanjo()
    cg_context.scout_api_ = MockScoutApi(cg_context)
    return MockHousekeeperMipDNAReportAPI(cg_context, cg_context.meta_apis["analysis_api"])


@pytest.fixture(scope="function")
def report_api_balsamic(
    cg_context: CGConfig, lims_samples: list[dict], report_store: Store
) -> BalsamicReportAPI:
    """BALSAMIC ReportAPI fixture."""
    cg_context.meta_apis["analysis_api"] = MockBalsamicAnalysis(cg_context)
    cg_context.status_db_ = report_store
    cg_context.lims_api_ = MockLimsAPI(cg_context, lims_samples)
    cg_context.scout_api_ = MockScoutApi(cg_context)
    return BalsamicReportAPI(cg_context, cg_context.meta_apis["analysis_api"])


@pytest.fixture(scope="function")
def report_api_rnafusion(
    rnafusion_context: CGConfig, lims_samples: list[dict]
) -> RnafusionReportAPI:
    """Rnafusion report API fixture."""
    rnafusion_context.lims_api_ = MockLimsAPI(rnafusion_context, lims_samples)
    rnafusion_context.scout_api_ = MockScoutApi(rnafusion_context)
    return RnafusionReportAPI(rnafusion_context, rnafusion_context.meta_apis["analysis_api"])


@pytest.fixture(scope="function")
def case_mip_dna(case_id: str, report_api_mip_dna: MipDNAReportAPI) -> Case:
    """MIP DNA case instance."""
    return report_api_mip_dna.status_db.get_case_by_internal_id(internal_id=case_id)


@pytest.fixture(scope="function")
def case_balsamic(case_id: str, report_api_balsamic: BalsamicReportAPI) -> Case:
    """BALSAMIC case instance."""
    return report_api_balsamic.status_db.get_case_by_internal_id(internal_id=case_id)


@pytest.fixture(scope="function")
def case_samples_data(case_id: str, report_api_mip_dna: MipDNAReportAPI):
    """MIP DNA family sample object."""
    return report_api_mip_dna.status_db.get_case_samples_by_case_id(case_internal_id=case_id)


@pytest.fixture(scope="function")
def mip_analysis_api(cg_context: CGConfig) -> MockMipAnalysis:
    """MIP analysis mock data."""
    return MockMipAnalysis(config=cg_context, pipeline=Pipeline.MIP_DNA)


@pytest.fixture(scope="session")
def lims_family(fixtures_dir: Path) -> dict:
    """Returns a lims-like case of samples."""
    return ReadFile.get_content_from_file(
        file_format=FileFormat.JSON, file_path=Path(fixtures_dir, "report", "lims_family.json")
    )


@pytest.fixture(scope="session")
def lims_samples(lims_family: dict) -> list[dict]:
    """Returns the samples of a lims case."""
    return lims_family["samples"]


@pytest.fixture(scope="function", autouse=True)
def report_store(analysis_store, helpers, timestamp_yesterday):
    """A mock store instance for report testing."""
    case = analysis_store.get_cases()[0]
    helpers.add_analysis(
        analysis_store, case, pipeline=Pipeline.MIP_DNA, started_at=timestamp_yesterday
    )
    helpers.add_analysis(analysis_store, case, pipeline=Pipeline.MIP_DNA, started_at=datetime.now())
    # Mock sample dates to calculate processing times
    for family_sample in analysis_store.get_case_samples_by_case_id(
        case_internal_id=case.internal_id
    ):
        family_sample.sample.ordered_at = timestamp_yesterday - timedelta(days=2)
        family_sample.sample.received_at = timestamp_yesterday - timedelta(days=1)
        family_sample.sample.prepared_at = timestamp_yesterday
        family_sample.sample.last_sequenced_at = timestamp_yesterday
        family_sample.sample.delivered_at = datetime.now()
    return analysis_store


@pytest.fixture(scope="session")
def rnafusion_validated_metrics() -> dict[str, str]:
    """Return Rnafusion raw analysis metrics dictionary."""
    return {
        "gc_content": "51.7",
        "ribosomal_bases": "65.81",
        "q20_rate": "97.48",
        "q30_rate": "92.95",
        "mapped_reads": "96.53",
        "rin": "10.0",
        "input_amount": "300.0",
        "insert_size": "N/A",
        "insert_size_peak": "N/A",
        "mean_length_r1": "99.0",
        "million_read_pairs": "75.0",
        "bias_5_3": "1.12",
        "pct_adapter": "12.01",
        "duplicates": "14.86",
        "mrna_bases": "85.97",
        "pct_surviving": "99.42",
        "uniquely_mapped_reads": "91.02",
    }
