from flask import current_app as app

from atst.database import db
from atst.models.task_order import TaskOrder
from atst.models.dd_254 import DD254
from . import BaseDomainClass
from atst.domain.portfolios import Portfolios
from atst.domain.permission_sets import PermissionSets


class TaskOrderError(Exception):
    pass


class TaskOrders(BaseDomainClass):
    model = TaskOrder
    resource_name = "task_order"

    SECTIONS = {
        "app_info": [
            "portfolio_name",
            "scope",
            "defense_component",
            "app_migration",
            "native_apps",
            "complexity",
            "dev_team",
            "team_experience",
        ],
        "funding": [
            "performance_length",
            "csp_estimate",
            "clin_01",
            "clin_02",
            "clin_03",
            "clin_04",
        ],
        "oversight": [
            "ko_first_name",
            "ko_last_name",
            "ko_email",
            "ko_phone_number",
            "cor_first_name",
            "cor_last_name",
            "cor_email",
            "cor_phone_number",
            "so_first_name",
            "so_last_name",
            "so_email",
            "so_phone_number",
        ],
    }

    UNCLASSIFIED_FUNDING = ["performance_length", "csp_estimate", "clin_01", "clin_03"]

    @classmethod
    def create(cls, creator, portfolio):
        task_order = TaskOrder(portfolio=portfolio, creator=creator)

        db.session.add(task_order)
        db.session.commit()

        return task_order

    @classmethod
    def update(cls, task_order, **kwargs):
        for key, value in kwargs.items():
            setattr(task_order, key, value)

        db.session.add(task_order)
        db.session.commit()

        return task_order

    @classmethod
    def section_completion_status(cls, task_order, section):
        if section in TaskOrders.mission_owner_sections():
            passed = []
            failed = []

            for attr in TaskOrders.SECTIONS[section]:
                if getattr(task_order, attr) is not None:
                    passed.append(attr)
                else:
                    failed.append(attr)

            if not failed:
                return "complete"
            elif passed and failed:
                return "draft"

        return "incomplete"

    @classmethod
    def all_sections_complete(cls, task_order):
        for section in TaskOrders.SECTIONS.keys():
            if (
                TaskOrders.section_completion_status(task_order, section)
                is not "complete"
            ):
                return False

        return True

    @classmethod
    def can_ko_sign(cls, task_order):
        return (
            TaskOrders.all_sections_complete(task_order)
            and DD254s.is_complete(task_order.dd_254)
            and not TaskOrders.is_signed_by_ko(task_order)
        )

    @classmethod
    def is_signed_by_ko(cls, task_order):
        return task_order.signer_dod_id is not None

    @classmethod
    def mission_owner_sections(cls):
        section_list = TaskOrders.SECTIONS
        if not app.config.get("CLASSIFIED"):
            section_list["funding"] = TaskOrders.UNCLASSIFIED_FUNDING
        return section_list

    OFFICERS = [
        "contracting_officer",
        "contracting_officer_representative",
        "security_officer",
    ]

    @classmethod
    def add_officer(cls, task_order, officer_type, officer_data):
        if officer_type in TaskOrders.OFFICERS:
            portfolio = task_order.portfolio

            existing_member = next(
                (
                    member
                    for member in portfolio.members
                    if member.user.dod_id == officer_data["dod_id"]
                ),
                None,
            )

            if existing_member:
                portfolio_user = existing_member.user
            else:
                member = Portfolios.create_member(
                    portfolio,
                    {
                        **officer_data,
                        "permission_sets": [PermissionSets.EDIT_PORTFOLIO_FUNDING],
                    },
                )
                portfolio_user = member.user

            setattr(task_order, officer_type, portfolio_user)

            db.session.add(task_order)
            db.session.commit()

            return portfolio_user
        else:
            raise TaskOrderError(
                "{} is not an officer role on task orders".format(officer_type)
            )

    @classmethod
    def add_dd_254(user, task_order, dd_254_data):
        dd_254 = DD254(**dd_254_data)
        task_order.dd_254 = dd_254

        db.session.add(task_order)
        db.session.commit()


class DD254s:
    # TODO: standin implementation until we have a real download,
    # sign, and verify process for the DD 254 PDF
    @classmethod
    def is_complete(cls, dd254):
        if dd254 is None:
            return False

        for col in DD254.__table__.columns:
            if getattr(dd254, col.name) is None:
                return False

        return True
