"""tests for Cytoscape API requests, needs running Cytoscape server;
Tests assume that no Cytoscape instance is running.
The validation of the correct behaviour can only be done with a running instance,
especially for layout and formatting tasks. A static test suite is not helpful in
this case.
"""

import py4cytoscape as p4c
import pytest
from py4cytoscape.exceptions import CyError
from requests.exceptions import RequestException

from lang_main.constants import CYTO_BASE_NETWORK_NAME, CYTO_SELECTION_PROPERTY
from lang_main.errors import GraphRenderError
from lang_main.render import cytoscape as cyto

_cyto_available: bool = True
try:
    p4c.cytoscape_ping()
except RequestException:
    _cyto_available = False


@pytest.fixture(scope='module')
def avail() -> bool:
    return _cyto_available


@pytest.mark.cyto
def test_verify_connection(avail):
    if avail:
        cyto.verify_connection()
    else:
        with pytest.raises(RequestException):
            cyto.verify_connection()


def test_verify_graph_render_size(data_tk_graph_built):
    cyto.verify_graph_render_size(
        data_tk_graph_built, max_node_count=None, max_edge_count=None
    )

    with pytest.raises(GraphRenderError):
        cyto.verify_graph_render_size(
            data_tk_graph_built, max_node_count=0, max_edge_count=None
        )

    with pytest.raises(GraphRenderError):
        cyto.verify_graph_render_size(
            data_tk_graph_built, max_node_count=None, max_edge_count=0
        )


@pytest.mark.cyto
def test_change_default_layout(avail):
    if avail:
        cyto.change_default_layout()
    else:
        with pytest.raises(RequestException):
            cyto.change_default_layout()


@pytest.mark.cyto
def test_import_to_cytoscape(avail, data_tk_graph_built):
    if avail:
        cyto.import_to_cytoscape(data_tk_graph_built)
    else:
        with pytest.raises(RequestException):
            cyto.import_to_cytoscape(data_tk_graph_built)


@pytest.mark.cyto
def test_verify_table_property(avail, data_tk_graph_built):
    if avail:
        cyto.import_to_cytoscape(data_tk_graph_built)
        contained = cyto.verify_table_property(property='TEST', table_type='node')
        assert not contained
        contained = cyto.verify_table_property(property='name', table_type='node')
        assert contained
        contained = cyto.verify_table_property(property='degree_weighted', table_type='node')
        assert contained
    else:
        with pytest.raises(RequestException):
            contained = cyto.verify_table_property(property='TEST', table_type='node')


@pytest.mark.cyto
def test_analyse_network(avail, data_tk_graph_built):
    if avail:
        cyto.import_to_cytoscape(data_tk_graph_built)
        cyto.analyse_network()
        contained = cyto.verify_table_property(property='name', table_type='node')
        assert contained
        contained = cyto.verify_table_property(
            property=CYTO_SELECTION_PROPERTY, table_type='node'
        )
        assert contained
    else:
        with pytest.raises(RequestException):
            cyto.analyse_network(data_tk_graph_built)


@pytest.mark.cyto
def test_reset_current_network_to_base(avail):
    if avail:
        cyto.reset_current_network_to_base()
    else:
        with pytest.raises(RequestException):
            cyto.reset_current_network_to_base()


@pytest.mark.cyto
def test_fit_content(avail, data_tk_graph_built):
    if avail:
        cyto.import_to_cytoscape(data_tk_graph_built)
        cyto.fit_content()
    else:
        with pytest.raises(RequestException):
            cyto.fit_content()


@pytest.mark.cyto
def test_export_network_to_image(avail, tmp_path, data_tk_graph_built):
    filename = 'test_export'
    if avail:
        cyto.import_to_cytoscape(data_tk_graph_built)
        cyto.export_network_to_image(filename=filename, target_folder=tmp_path)
        target_file = tmp_path / f'{filename}.svg'
        assert target_file.exists()
        assert target_file.name == f'{filename}.svg'
    else:
        with pytest.raises(RequestException):
            cyto.export_network_to_image(filename=filename, target_folder=tmp_path)


@pytest.mark.cyto
def test_layout_network(avail, data_tk_graph_built):
    if avail:
        cyto.import_to_cytoscape(data_tk_graph_built)
        cyto.layout_network()
    else:
        with pytest.raises(RequestException):
            cyto.layout_network()


@pytest.mark.cyto
def test_apply_style_to_network(avail, data_tk_graph_built, tmp_path):
    if avail:
        layout_not_existing = 'testing'
        pth_not_existing = tmp_path / 'test.xml'
        with pytest.raises(FileNotFoundError):
            cyto.apply_style_to_network(
                style_name=layout_not_existing,
                pth_to_stylesheet=pth_not_existing,
            )

        cyto.import_to_cytoscape(data_tk_graph_built)
        # not existing: so transfer necessary,
        # but fails nevertheless because style is imported
        # using the name provided by this style configuration
        with pytest.raises(CyError):
            cyto.apply_style_to_network(style_name=layout_not_existing)
        cyto.apply_style_to_network()
    else:
        with pytest.raises(RequestException):
            cyto.apply_style_to_network()


@pytest.mark.cyto
def test_get_subgraph_node_selection(avail, data_tk_graph_built):
    num_subgraphs = 2
    if avail:
        cyto.import_to_cytoscape(data_tk_graph_built)
        cyto.analyse_network()
        suids = cyto.get_subgraph_node_selection(num_subgraphs=num_subgraphs)
        assert len(suids) > 0
    else:
        with pytest.raises(RequestException):
            cyto.get_subgraph_node_selection(num_subgraphs=num_subgraphs)


@pytest.mark.cyto
def test_select_neighbours_of_node(avail, data_tk_graph_built):
    num_subgraphs = 2
    if avail:
        cyto.import_to_cytoscape(data_tk_graph_built)
        suids = cyto.get_subgraph_node_selection(num_subgraphs=num_subgraphs)
        assert len(suids) > 0
        cyto.select_neighbours_of_node(suids[0], neighbour_iter_depth=2)
    else:
        with pytest.raises(RequestException):
            cyto.select_neighbours_of_node(123, neighbour_iter_depth=2)


@pytest.mark.cyto
def test_make_subnetwork(avail, data_tk_graph_built, tmp_path):
    if avail:
        cyto.import_to_cytoscape(data_tk_graph_built)
        suids = cyto.get_subgraph_node_selection(num_subgraphs=2)
        assert len(suids) > 0
        cyto.select_neighbours_of_node(suids[0], neighbour_iter_depth=2)
        cyto.make_subnetwork(0, target_folder=tmp_path, export_image=True)
        subnetwork_name = CYTO_BASE_NETWORK_NAME + '_sub_1'
        networks = p4c.get_network_list()
        assert len(networks) > 1
        file = (tmp_path / subnetwork_name).with_suffix('.svg')
        assert file.exists()
    else:
        with pytest.raises(RequestException):
            cyto.make_subnetwork(0, target_folder=tmp_path, export_image=True)


@pytest.mark.cyto
def test_build_subnetworks(avail, data_tk_graph_built, tmp_path):
    if avail:
        cyto.import_to_cytoscape(data_tk_graph_built)
        suids = cyto.get_subgraph_node_selection(num_subgraphs=1)
        assert len(suids) > 0
        cyto.build_subnetworks(suids, export_image=True, target_folder=tmp_path)
        subnetwork_name = CYTO_BASE_NETWORK_NAME + '_sub_1'
        networks = p4c.get_network_list()
        assert len(networks) > 1
        file = (tmp_path / subnetwork_name).with_suffix('.svg')
        assert file.exists()
    else:
        with pytest.raises(RequestException):
            cyto.build_subnetworks([123], export_image=True, target_folder=tmp_path)
