from datetime import datetime

from pydantic import BaseModel, Extra
from ichec_django_core.client import (
    Identifiable,
    Timestamped,
    FormCreate,
    FormDetail,
    FormFieldDetail,
    register_types,
    PopulatedFormCreate,
    PopulatedFormDetail,
    PopulatedFormUpdate,
    MemberList,
)


class AccessCallBase(BaseModel, frozen=True):

    title: str
    description: str
    status: str
    closing_date: datetime
    selectable_facilities: list[str] = []


class AccessCallCreate(AccessCallBase, frozen=True):

    form: FormCreate
    use_facility_review: bool
    public: bool
    coordinator: str
    board_chair: str
    board_members: list[str] = []
    auto_assign_reviewers: bool
    request_dates: bool
    notify_reviewers: bool
    require_all_reviews: bool

    class Config:
        extra = Extra.forbid


class AccessCallList(Timestamped, AccessCallBase, frozen=True):
    resolved_contact_email: str

    class Config:
        extra = Extra.forbid


class AccessCallPublicDetail(AccessCallList, frozen=True):
    resolved_contact_email: str
    form: FormDetail
    request_dates: bool

    class Config:
        extra = Extra.forbid

    def get_field(self, key: str) -> FormFieldDetail | None:
        for group in self.form.groups:
            for field in group.fields:
                if field.key == key:
                    return field
        return None


class AccessCallReviewerDetail(AccessCallPublicDetail, frozen=True):
    coordinator: str
    board_chair: str
    review_template: str | None
    facility_review_template: str | None
    test_report_template: str | None
    is_reviewer: bool | None

    class Config:
        extra = Extra.forbid


class AccessCallDetailBase(AccessCallReviewerDetail, frozen=True):

    applications_summary: str | None
    use_facility_review: bool
    public: bool
    decision_template: str | None
    auto_assign_reviewers: bool
    require_all_reviews: bool
    is_coordinator: bool
    is_chair: bool
    notify_reviewers: bool


class AccessCallDetail(AccessCallDetailBase, frozen=True):

    board_members: list[MemberList] = []

    class Config:
        extra = Extra.forbid


class AccessCallUpdate(AccessCallDetailBase, frozen=True):

    board_members: list[str] = []

    class Config:
        extra = Extra.forbid

    @staticmethod
    def from_detail(detail) -> "AccessCallUpdate":
        dumped = detail.model_dump()
        dumped["board_members"] = [m.url for m in detail.board_members]
        return AccessCallUpdate(**dumped)


class ApplicationFieldValueBase(BaseModel, frozen=True):

    value: str
    field: str
    asset: str | None = None


class ApplicationFieldValueCreate(ApplicationFieldValueBase, frozen=True):
    pass


class ApplicationFieldValueDetail(Identifiable, ApplicationFieldValueBase, frozen=True):
    pass


class AccessApplicationBase(BaseModel, frozen=True):
    call: str
    facilities: list[str] = []
    chosen_facility: str | None = None
    request_start_date: datetime | None = None
    request_end_date: datetime | None = None
    dates_flexible: bool = True
    status: str = "CREATED"


class AccessApplicationList(Timestamped, AccessApplicationBase, frozen=True):
    pass


class AccessApplicationCreate(AccessApplicationBase, frozen=True):
    form: PopulatedFormCreate

    class Config:
        extra = Extra.forbid


class AccessApplicationDetail(Timestamped, AccessApplicationBase, frozen=True):
    applicant: str
    submitted: datetime | None = None
    form: PopulatedFormDetail
    call_title: str
    applicant_username: str
    is_selectable_facility_member: bool
    is_selected_facility_member: bool
    is_reviewer: bool
    is_call_coordinator: bool
    is_call_chair: bool
    summary: str | None
    reviewers: list[MemberList] = []

    class Config:
        extra = Extra.forbid

    def to_update(self):

        dump = self.model_dump()
        dump["form"] = self.form.to_update()
        dump["reviewers"] = [r.url for r in self.reviewers]
        return AccessApplicationUpdate(**dump)


class AccessApplicationUpdate(AccessApplicationDetail, frozen=True):
    form: PopulatedFormUpdate

    class Config:
        extra = Extra.forbid


class FacilityTestReportBase(BaseModel, frozen=True):
    datasets: list[str] = []
    confirmed_complies_data_mgmt: bool
    application: str
    facility: str


class FacilityTestReportCreate(FacilityTestReportBase, frozen=True):
    class Config:
        extra = Extra.forbid


class FacilityTestReportDetail(Timestamped, FacilityTestReportBase, frozen=True):
    creator: str
    report: str | None
    facility_name: str
    facility_acronym: str
    creator_contact: str
    applicant_contact: str
    call_title: str
    confirmed_complies_data_mgmt: bool

    class Config:
        extra = Extra.forbid


class AccessApplicationFacilityReview(BaseModel, frozen=True):
    confirmed_preapplication_discussion: bool
    confirmed_app_info_in_line_with_discussion: bool
    supporting_comments: str
    facility: str
    application: str

    class Config:
        extra = Extra.forbid


class AccessApplicationBoardReviewBase(BaseModel, frozen=True):
    decision: str
    comments: str
    application: str


class AccessApplicationBoardReviewCreate(AccessApplicationBoardReviewBase, frozen=True):
    class Config:
        extra = Extra.forbid


class AccessApplicationBoardReviewDetail(
    Timestamped, AccessApplicationBoardReviewCreate, frozen=True
):
    reviewer: str
    supporting_document: str | None

    class Config:
        extra = Extra.forbid


class AccessApplicationBoardDecisionBase(BaseModel, frozen=True):
    decision: str
    comments: str
    application: str
    selected_facility: str
    supporting_document: str | None


class AccessApplicationBoardDecisionCreate(
    AccessApplicationBoardDecisionBase, frozen=True
):
    class Config:
        extra = Extra.forbid


class AccessApplicationBoardDecisionDetail(
    Timestamped, AccessApplicationBoardDecisionBase, frozen=True
):
    reviewer: str

    class Config:
        extra = Extra.forbid


register_types(
    "access_calls",
    {
        "create": AccessCallCreate,
        "detail-public": AccessCallPublicDetail,
        "detail-reviewer": AccessCallReviewerDetail,
        "detail": AccessCallDetail,
        "update": AccessCallUpdate,
        "list": AccessCallList,
    },
)

register_types(
    "access_applications",
    {
        "create": AccessApplicationCreate,
        "detail": AccessApplicationDetail,
        "list": AccessApplicationList,
    },
)

register_types(
    "access_application_board_reviews",
    {
        "create": AccessApplicationBoardReviewCreate,
        "detail": AccessApplicationBoardReviewDetail,
    },
)

register_types(
    "access_application_board_decisions",
    {
        "create": AccessApplicationBoardDecisionCreate,
        "detail": AccessApplicationBoardDecisionDetail,
    },
)

register_types(
    "facility_test_reports",
    {"create": FacilityTestReportCreate, "detail": FacilityTestReportDetail},
)
