import pytest
from flask import url_for

from atst.domain.task_orders import TaskOrders
from atst.domain.permission_sets import PermissionSets
from atst.models.attachment import Attachment
from atst.routes.task_orders.new import ShowTaskOrderWorkflow, UpdateTaskOrderWorkflow
from atst.utils.localization import translate

from tests.factories import (
    UserFactory,
    TaskOrderFactory,
    PortfolioFactory,
    PortfolioRoleFactory,
)


@pytest.fixture
def portfolio():
    return PortfolioFactory.create()


@pytest.fixture
def user():
    return UserFactory.create()


class TestShowTaskOrderWorkflow:
    def test_portfolio_when_task_order_exists(self):
        portfolio = PortfolioFactory.create()
        task_order = TaskOrderFactory(portfolio=portfolio)
        assert portfolio.num_task_orders > 0

        workflow = ShowTaskOrderWorkflow(
            user=task_order.creator, task_order_id=task_order.id
        )
        assert portfolio == workflow.portfolio

    def test_portfolio_with_portfolio_id(self):
        user = UserFactory.create()
        portfolio = PortfolioFactory.create(owner=user)
        workflow = ShowTaskOrderWorkflow(
            user=portfolio.owner, portfolio_id=portfolio.id
        )
        assert portfolio == workflow.portfolio


def test_new_task_order(client, user_session):
    creator = UserFactory.create()
    user_session()
    response = client.get(url_for("task_orders.new", screen=1))
    assert response.status_code == 200


def post_to_task_order_step(client, data, screen, task_order_id=None):
    return client.post(
        url_for("task_orders.update", screen=screen, task_order_id=task_order_id),
        data=data,
        follow_redirects=False,
    )


def slice_data_for_section(task_order_data, section):
    attrs = TaskOrders.SECTIONS[section]
    return {k: v for k, v in task_order_data.items() if k in attrs}


def serialize_dates(data):
    if not data:
        return data

    dates = {
        k: v.strftime("%m/%d/%Y") for k, v in data.items() if hasattr(v, "strftime")
    }

    data.update(dates)

    return data


def test_new_to_can_edit_pf_attributes_screen_1():
    portfolio = PortfolioFactory.create()
    workflow = ShowTaskOrderWorkflow(user=portfolio.owner)
    assert not workflow.pf_attributes_read_only


def test_new_pf_can_edit_pf_attributes_on_back_navigation():
    portfolio = PortfolioFactory.create()
    pf_task_order = TaskOrderFactory(portfolio=portfolio)
    pf_workflow = ShowTaskOrderWorkflow(
        user=pf_task_order.creator, task_order_id=pf_task_order.id
    )
    assert not pf_workflow.pf_attributes_read_only


def test_to_on_pf_cannot_edit_pf_attributes():
    portfolio = PortfolioFactory.create()
    pf_task_order = TaskOrderFactory(portfolio=portfolio)

    workflow = ShowTaskOrderWorkflow(user=portfolio.owner, portfolio_id=portfolio.id)
    assert portfolio.num_task_orders == 1
    assert workflow.pf_attributes_read_only

    second_task_order = TaskOrderFactory(portfolio=portfolio)
    second_workflow = ShowTaskOrderWorkflow(
        user=portfolio.owner, task_order_id=second_task_order.id
    )
    assert portfolio.num_task_orders > 1
    assert second_workflow.pf_attributes_read_only


def test_create_new_task_order(client, user_session, pdf_upload):
    creator = UserFactory.create()
    user_session(creator)

    task_order_data = TaskOrderFactory.dictionary()
    app_info_data = slice_data_for_section(task_order_data, "app_info")
    portfolio_name = "Mos Eisley"
    defense_component = "Defense Health Agency"
    app_info_data["portfolio_name"] = portfolio_name
    app_info_data["defense_component"] = defense_component

    response = client.post(
        url_for("task_orders.update", screen=1),
        data=app_info_data,
        follow_redirects=False,
    )
    assert url_for("task_orders.new", screen=2) in response.headers["Location"]

    created_task_order_id = response.headers["Location"].split("/")[-1]
    created_task_order = TaskOrders.get(created_task_order_id)
    assert created_task_order.portfolio is not None
    assert created_task_order.portfolio.name == portfolio_name
    assert created_task_order.portfolio.defense_component == defense_component

    funding_data = slice_data_for_section(task_order_data, "funding")
    funding_data = serialize_dates(funding_data)
    funding_data["csp_estimate"] = pdf_upload
    response = client.post(
        response.headers["Location"], data=funding_data, follow_redirects=False
    )
    assert url_for("task_orders.new", screen=3) in response.headers["Location"]

    oversight_data = slice_data_for_section(task_order_data, "oversight")
    response = client.post(
        response.headers["Location"], data=oversight_data, follow_redirects=False
    )
    assert url_for("task_orders.new", screen=4) in response.headers["Location"]


def test_create_new_task_order_for_portfolio(client, user_session):
    portfolio = PortfolioFactory.create()
    creator = portfolio.owner
    user_session(creator)

    task_order_data = TaskOrderFactory.dictionary()
    app_info_data = slice_data_for_section(task_order_data, "app_info")
    app_info_data["portfolio_name"] = portfolio.name
    app_info_data["defense_component"] = portfolio.defense_component

    response = client.post(
        url_for("task_orders.update", screen=1, portfolio_id=portfolio.id),
        data=app_info_data,
        follow_redirects=False,
    )
    assert url_for("task_orders.new", screen=2) in response.headers["Location"]

    created_task_order_id = response.headers["Location"].split("/")[-1]
    created_task_order = TaskOrders.get(created_task_order_id)
    assert created_task_order.portfolio_name == portfolio.name
    assert created_task_order.defense_component == portfolio.defense_component
    assert created_task_order.portfolio == portfolio


def test_task_order_form_shows_errors(client, user_session, task_order):
    creator = task_order.creator
    user_session(creator)

    task_order_data = TaskOrderFactory.dictionary()
    funding_data = slice_data_for_section(task_order_data, "funding")
    funding_data = serialize_dates(funding_data)
    funding_data.update({"clin_01": "one milllllion dollars"})

    response = client.post(
        url_for("task_orders.update", screen=2, task_order_id=task_order.id),
        data=funding_data,
        follow_redirects=False,
    )

    body = response.data.decode()
    assert "There were some errors" in body
    assert "Not a valid decimal" in body


def test_task_order_validates_email_address(client, user_session, task_order):
    creator = task_order.creator
    user_session(creator)

    task_order_data = TaskOrderFactory.dictionary()
    oversight_data = slice_data_for_section(task_order_data, "oversight")
    oversight_data.update({"ko_email": "not an email"})

    response = client.post(
        url_for("task_orders.update", screen=3, task_order_id=task_order.id),
        data=oversight_data,
        follow_redirects=False,
    )

    body = response.data.decode()
    assert "There were some errors" in body
    assert "Invalid email" in body


def test_review_screen_when_all_sections_complete(client, user_session, task_order):
    user_session(task_order.creator)
    response = client.get(
        url_for("task_orders.new", screen=4, task_order_id=task_order.id)
    )

    body = response.data.decode()
    assert translate("task_orders.form.draft_alert_title") not in body
    assert response.status_code == 200


def test_review_screen_when_not_all_sections_complete(client, user_session, task_order):
    TaskOrders.update(task_order, clin_01=None)
    user_session(task_order.creator)
    response = client.get(
        url_for("task_orders.new", screen=4, task_order_id=task_order.id)
    )

    body = response.data.decode()
    assert translate("task_orders.form.draft_alert_title") in body
    assert response.status_code == 200


@pytest.fixture
def task_order():
    user = UserFactory.create()
    portfolio = PortfolioFactory.create(owner=user)
    attachment = Attachment(filename="sample_attachment", object_name="sample")

    return TaskOrderFactory.create(
        creator=user, portfolio=portfolio, csp_estimate=attachment
    )


def test_show_task_order(task_order):
    workflow = ShowTaskOrderWorkflow(task_order.creator)
    assert workflow.task_order is None
    another_workflow = ShowTaskOrderWorkflow(
        task_order.creator, task_order_id=task_order.id
    )
    assert another_workflow.task_order == task_order


def test_show_task_order_form_list_data():
    complexity = ["oconus", "tactical_edge"]
    user = UserFactory.create()
    portfolio = PortfolioFactory.create(owner=user)
    task_order = TaskOrderFactory.create(
        creator=user, portfolio=portfolio, complexity=complexity
    )
    workflow = ShowTaskOrderWorkflow(user, task_order_id=task_order.id)

    assert workflow.form.complexity.data == complexity


def test_show_task_order_form(task_order):
    workflow = ShowTaskOrderWorkflow(task_order.creator)
    assert not workflow.form.data["app_migration"]
    another_workflow = ShowTaskOrderWorkflow(
        task_order.creator, task_order_id=task_order.id
    )
    assert (
        another_workflow.form.data["defense_component"] == task_order.defense_component
    )


def test_show_task_order_display_screen(task_order):
    workflow = ShowTaskOrderWorkflow(task_order.creator, task_order_id=task_order.id)
    screens = workflow.display_screens
    # every form section is complete
    for i in range(2):
        assert screens[i]["completion"] == "complete"
    # the review section is not
    assert screens[3]["completion"] == "incomplete"


def test_update_task_order_with_no_task_order():
    user = UserFactory.create()
    to_data = TaskOrderFactory.dictionary()
    workflow = UpdateTaskOrderWorkflow(user, to_data)
    assert workflow.task_order is None
    workflow.update()
    assert workflow.task_order
    assert workflow.task_order.scope == to_data["scope"]


def test_update_task_order_with_existing_task_order(task_order):
    to_data = serialize_dates(TaskOrderFactory.dictionary())
    workflow = UpdateTaskOrderWorkflow(
        task_order.creator, to_data, screen=2, task_order_id=task_order.id
    )
    assert workflow.task_order.start_date != to_data["start_date"]
    workflow.update()
    assert workflow.task_order.start_date.strftime("%m/%d/%Y") == to_data["start_date"]


def test_update_to_redirects_to_ko_review(client, user_session, task_order):
    ko = UserFactory.create()
    task_order.contracting_officer = ko
    PortfolioRoleFactory.create(
        user=ko,
        portfolio=task_order.portfolio,
        permission_sets=[PermissionSets.get(PermissionSets.EDIT_PORTFOLIO_FUNDING)],
    )
    user_session(ko)
    url = url_for("task_orders.ko_review", task_order_id=task_order.id)
    response = client.post(
        url_for("task_orders.new", screen=1, task_order_id=task_order.id, next=url)
    )
    body = response.data.decode()

    assert url in body
    assert response.status_code == 302


def test_other_text_not_saved_if_other_not_checked(task_order):
    to_data = {
        **TaskOrderFactory.dictionary(),
        "complexity": ["conus"],
        "complexity_other": "quite complex",
    }
    workflow = UpdateTaskOrderWorkflow(
        task_order.creator, to_data, task_order_id=task_order.id
    )
    workflow.update()
    assert not workflow.task_order.complexity_other


def test_cor_data_set_to_user_data_if_am_cor_is_checked(task_order):
    to_data = {**task_order.to_dictionary(), "am_cor": True}
    workflow = UpdateTaskOrderWorkflow(task_order.creator, to_data, 3, task_order.id)
    workflow.update()
    assert task_order.cor_dod_id == task_order.creator.dod_id


def test_review_task_order_form(client, user_session, task_order):
    user_session(task_order.creator)

    for idx, section in enumerate(TaskOrders.SECTIONS):
        response = client.get(
            url_for("task_orders.new", screen=idx + 1, task_order_id=task_order.id)
        )

        assert response.status_code == 200


def test_update_task_order_clears_unnecessary_other_responses():
    user = UserFactory.create()
    to_data = TaskOrderFactory.dictionary()
    to_data["complexity"] = ["storage"]
    to_data["complexity_other"] = "something else"
    to_data["dev_team"] = ["civilians"]
    to_data["dev_team_other"] = "something else"
    workflow = UpdateTaskOrderWorkflow(user, to_data)
    assert workflow.task_order_form_data["complexity_other"] is None
    assert workflow.task_order_form_data["dev_team_other"] is None


def test_mo_redirected_to_build_page(client, user_session, portfolio):
    user_session(portfolio.owner)
    task_order = TaskOrderFactory.create(portfolio=portfolio)

    response = client.get(
        url_for("task_orders.new", screen=1, task_order_id=task_order.id)
    )
    assert response.status_code == 200
