import pandas as pd
from usdm_excel.study_product_sheet.study_product_organization_role_sheet import (
    StudyProductOrganizationRoleSheet,
)
from usdm_model.organization import Organization
from usdm_model.administrable_product import AdministrableProduct
from usdm_model.medical_device import MedicalDevice
from usdm_excel.globals import Globals
from tests.test_factory import Factory


def test_create(factory, mocker, globals):
    data = {
        "name": ["AP1", "AP2", "AP3"],
        "description": ["Desc One", "Desc Two", "Desc Three"],
        "label": ["Lable 1", "L2", "L3"],
        "organization": ["Sponsor 1", "Sponsor 2", "Sponsor 3"],
        "role": ["Manufacturer", "Supplier", "Supplier"],
        "appliesTo": ["Product 1", "Device 1", "Product 1, Device 1"],
    }
    expected_1 = (
        '{"id": "POR_1", "name": "AP1", "label": "Lable 1", "description": "Desc One", '
        '"code": {"id": "C_18", "code": "C99915x1", "codeSystem": "http://www.cdisc.org", "codeSystemVersion": "2024-09-27", "decode": "Manufacturer", "instanceType": "Code"}, '
        '"appliesToIds": ["AP_1"], "organizationId": "O_1", '
        '"instanceType": "ProductOrganizationRole"}'
    )
    expected_2 = (
        '{"id": "POR_2", "name": "AP2", "label": "L2", "description": "Desc Two", '
        '"code": {"id": "C_19", "code": "C99915x2", "codeSystem": "http://www.cdisc.org", "codeSystemVersion": "2024-09-27", "decode": "Supplier", "instanceType": "Code"}, '
        '"appliesToIds": ["MD_1"], "organizationId": "O_2", '
        '"instanceType": "ProductOrganizationRole"}'
    )
    expected_3 = (
        '{"id": "POR_3", "name": "AP3", "label": "L3", "description": "Desc Three", '
        '"code": {"id": "C_20", "code": "C99915x2", "codeSystem": "http://www.cdisc.org", "codeSystemVersion": "2024-09-27", "decode": "Supplier", "instanceType": "Code"}, '
        '"appliesToIds": ["AP_1", "MD_1"], "organizationId": "O_3", '
        '"instanceType": "ProductOrganizationRole"}'
    )
    mock_id = mocker.patch("usdm_excel.id_manager.IdManager.build_id")
    mock_id.side_effect = [
        "C_1",
        "C_2",
        "C_3",
        "O_1",
        "O_2",
        "O_3",
        "C_4",
        "C_5",
        "C_6",
        "C_7",
        "C_8",
        "C_9",
        "C_10",
        "C_11",
        "C_12",
        "C_13",
        "AP_1",
        "AP_2",
        "AP_3",
        "C_15",
        "C_16",
        "C_17",
        "MD_1",
        "MD_2",
        "MD_3",
        "C_18",
        "POR_1",
        "C_19",
        "POR_2",
        "C_20",
        "POR_3",
        "X_5",
        "X_6",
        "X_7",
        "X_8",
        "X_9",
        "X_10",
        "X_11",
        "X_12",
    ]
    _setup(mocker, globals, data)
    _create_orgs(factory, globals)
    _create_products(factory, globals)
    _create_devices(factory, globals)
    item = StudyProductOrganizationRoleSheet("", globals)
    assert len(item.items) == 3
    assert item.items[0].to_json() == expected_1
    assert item.items[1].to_json() == expected_2
    assert item.items[2].to_json() == expected_3


def test_create_empty(mocker, globals):
    data = {}
    _setup(mocker, globals, data)
    item = StudyProductOrganizationRoleSheet("", globals)
    assert len(item.items) == 0


def test_read_cell_by_name_error(mocker, globals):
    data = {
        "name": ["AP1"],
        "description": ["Desc One"],
        "label": ["Lable 1"],
        "role": ["Investigator"],
    }
    mock_error = mocker.patch("usdm_excel.errors_and_logging.errors.Errors.add")
    mock_id = mocker.patch("usdm_excel.id_manager.IdManager.build_id")
    mock_id.side_effect = ["Code_1", "Abbreviation_1"]
    _setup(mocker, globals, data)
    item = StudyProductOrganizationRoleSheet("", globals)
    assert mock_error.call_count == 2
    mock_error.assert_has_calls(
        [
            mocker.call(
                "studyProductOrganizationRoles",
                1,
                -1,
                "Error attempting to read cell 'organization'. Exception: Failed to detect column(s) 'organization' in sheet",
                40,
            ),
            mocker.call(
                "studyProductOrganizationRoles",
                None,
                None,
                "Exception. Error ['NoneType' object has no attribute 'id'] while reading sheet 'studyProductOrganizationRoles'. See log for additional details.",
                40,
            ),
        ]
    )


def _setup(mocker, globals, data):
    globals.cross_references.clear()
    mock_present = mocker.patch("usdm_excel.base_sheet.BaseSheet._sheet_present")
    mock_present.side_effect = [True]
    mocked_open = mocker.mock_open(read_data="File")
    mocker.patch("builtins.open", mocked_open)
    mock_read = mocker.patch("pandas.read_excel")
    mock_read.return_value = pd.DataFrame.from_dict(data)


def _create_orgs(factory: Factory, globals: Globals):
    items = [
        {
            "name": "Sponsor 1",
            "type": factory.cdisc_code("C70793", "sponsor"),
            "identifier": "123456789",
            "identifierScheme": "DUNS",
            "legalAddress": None,
        },
        {
            "name": "Sponsor 2",
            "type": factory.cdisc_code("C70793", "sponsor"),
            "identifier": "222222222",
            "identifierScheme": "DUNS",
            "legalAddress": None,
        },
        {
            "name": "Sponsor 3",
            "type": factory.cdisc_code("C70793", "sponsor"),
            "identifier": "333333333",
            "identifierScheme": "DUNS",
            "legalAddress": None,
        },
    ]
    for item in items:
        instance = factory.item(Organization, item)
        globals.cross_references.add(item["name"], instance)


def _create_products(factory: Factory, globals: Globals):
    std_code = factory.cdisc_code("C70793", "XX1")
    items = [
        {
            "name": "Product 1",
            "productDesignation": factory.cdisc_code("C70793", "YYY"),
            "sourcing": factory.cdisc_code("C70793", "XXX"),
            "administrableDoseForm": factory.alias_code(std_code, []),
        },
        {
            "name": "Product 2",
            "productDesignation": factory.cdisc_code("C70793", "YYY"),
            "sourcing": factory.cdisc_code("C70793", "XXX"),
            "administrableDoseForm": factory.alias_code(std_code, []),
        },
        {
            "name": "Product 3",
            "productDesignation": factory.cdisc_code("C70793", "YYY"),
            "sourcing": factory.cdisc_code("C70793", "XXX"),
            "administrableDoseForm": factory.alias_code(std_code, []),
        },
    ]
    for item in items:
        instance = factory.item(AdministrableProduct, item)
        globals.cross_references.add(item["name"], instance)


def _create_devices(factory: Factory, globals: Globals):
    items = [
        {"name": "Device 1", "sourcing": factory.cdisc_code("C70793", "XXX")},
        {"name": "Device 2", "sourcing": factory.cdisc_code("C70793", "XXX")},
        {"name": "Device 3", "sourcing": factory.cdisc_code("C70793", "XXX")},
    ]
    for item in items:
        instance = factory.item(MedicalDevice, item)
        globals.cross_references.add(item["name"], instance)
