import datetime
import enum
from email.message import Message
from typing import Any

import msgspec


class TransactionTypeEnum(enum.Enum):
    # CURRENTLY USED
    CREATE = "Create"
    STATUS = "Status"
    CORRESPOND = "Correspond"
    COMMENT = "Comment"
    CUSTOM_FIELD = "CustomField"
    # GENERALY NOT USED
    ENABLED = "Enabled"
    DISABLED = "Disabled"
    SYSTEM_ERROR = "SystemError"
    AttachmentTruncate = "AttachmentTruncate"
    AttachmentDrop = "AttachmentDrop"
    AttachmentError = "AttachmentError"
    FORWARD_TRANSACTION = "Forward Transaction"
    FORWARD_TICKET = "Forward Ticket"
    COMMENT_EMAIL_RECORD = "CommentEmailRecord"
    EMAIL_RECORD = "EmailRecord"
    UNTAKE = "Untake"
    TAKE = "Take"
    FORCE = "Force"
    STEAL = "Steal"
    GIVE = "Give"
    ADD_WATCHER = "AddWatcher"
    DEL_WATCHER = "DelWatcher"
    SET_WATCHER = "SetWatcher"
    SUBJECT = "Subject"
    ADD_LINK = "AddLink"
    DELETE_LINK = "DeleteLink"
    TOLD = "Told"
    SET = "Set"
    SET_TIME_WORKED = "Set-TimeWorked"
    PURGE_TRANSACTION = "PurgeTransaction"
    ADD_REMINDER = "AddReminder"
    OPEN_REMINDER = "OpenReminder"
    RESOLVE_REMINDER = "ResolveReminder"
    RT_ASSET_SET_CATALOG = "RT::Asset-Set-Catalog"
    ADD_MEMBER = "AddMember"
    DELETE_MEMBER = "DeleteMember"
    ADD_MEMBERSHIP = "AddMembership"
    DELETE_MEMBERSHIP = "DeleteMembership"
    MUNGE = "Munge"
    SET_CONFIG = "SetConfig"
    DELETE_CONFIG = "DeleteConfig"
    GRANT_RIGHT = "GrantRight"
    REVOKE_RIGHT = "RevokeRight"


class GenericObjStruct(msgspec.Struct):
    id: str
    type: str
    url: str = msgspec.field(name="_url")


class UserObjStruct(GenericObjStruct): ...


class CustomFieldStruct(GenericObjStruct):
    name: str
    _values: list[str | None] = msgspec.field(name="values")

    @property
    def values(self) -> list[str]:
        return [x for x in self._values if x is not None and x != ""]


class EffectiveIdStruct(GenericObjStruct): ...


class QueueObjStruct(GenericObjStruct): ...


class TicketObjStruct(msgspec.Struct):
    admin_cc: list[str] = msgspec.field(name="AdminCc")
    cc: list[dict[str, Any]] = msgspec.field(name="Cc")
    created: datetime.datetime = msgspec.field(name="Created")
    creator: UserObjStruct = msgspec.field(name="Creator")
    custom_fields: list[CustomFieldStruct] = msgspec.field(name="CustomFields")
    effective_id: EffectiveIdStruct = msgspec.field(name="EffectiveId")
    final_priority_src: str = msgspec.field(name="FinalPriority")
    initial_priority_src: str = msgspec.field(name="InitialPriority")
    last_updated: datetime.datetime = msgspec.field(name="LastUpdated")
    last_updated_by: UserObjStruct = msgspec.field(name="LastUpdatedBy")
    priority_src: str = msgspec.field(name="Priority")
    queue: QueueObjStruct = msgspec.field(name="Queue")
    requestor: list[UserObjStruct] = msgspec.field(name="Requestor")
    status: str = msgspec.field(name="Status")
    subject: str = msgspec.field(name="Subject")
    time_estimated_src: str = msgspec.field(name="TimeEstimated")
    time_left_src: str = msgspec.field(name="TimeLeft")
    time_worked_src: str = msgspec.field(name="TimeWorked")
    type: str = msgspec.field(name="Type")
    id: int
    sla: str | None = msgspec.field(name="SLA", default=None)
    owner: UserObjStruct | None = msgspec.field(name="Owner", default=None)
    due: datetime.datetime | None = msgspec.field(name="Due", default=None)
    resolved: datetime.datetime | None = msgspec.field(name="Resolved", default=None)
    started: datetime.datetime | None = msgspec.field(name="Started", default=None)
    starts: datetime.datetime | None = msgspec.field(name="Starts", default=None)

    @property
    def final_priority(self) -> int | None:
        if self.final_priority_src.isdigit():
            return int(self.final_priority_src)
        return None

    @property
    def initial_priority(self) -> int | None:
        if self.initial_priority_src.isdigit():
            return int(self.initial_priority_src)
        return None

    @property
    def priority(self) -> int | None:
        if self.priority_src.isdigit():
            return int(self.priority_src)
        return None

    @property
    def time_estimated(self) -> int | None:
        if self.time_estimated_src.isdigit():
            return int(self.time_estimated_src)
        return None

    @property
    def time_worked(self) -> int | None:
        if self.time_worked_src.isdigit():
            return int(self.time_worked_src)
        return None

    @property
    def time_left(self) -> int | None:
        if self.time_left_src.isdigit():
            return int(self.time_left_src)
        return None


class TransactionStruct(msgspec.Struct):
    type: TransactionTypeEnum = msgspec.field(name="Type")
    created: datetime.datetime = msgspec.field(name="Created")
    time_taken_src: str = msgspec.field(name="TimeTaken")
    queue: str = msgspec.field(name="Queue")
    id: int
    host: str
    source_type: str
    timestamp: datetime.datetime
    creator: UserObjStruct = msgspec.field(name="Creator")
    object: GenericObjStruct = msgspec.field(name="Object")
    ticket_obj: TicketObjStruct | None = msgspec.field(name="TicketObj", default=None)
    data: str | None = msgspec.field(name="Data", default=None)
    field: GenericObjStruct | str | None = msgspec.field(name="Field", default=None)
    old_value: GenericObjStruct | str | None = msgspec.field(name="OldValue", default=None)
    new_value: GenericObjStruct | str | None = msgspec.field(name="NewValue", default=None)
    old_reference: GenericObjStruct | None = msgspec.field(name="OldReference", default=None)
    new_reference: GenericObjStruct | None = msgspec.field(name="NewReference", default=None)
    interface: str | None = msgspec.field(name="Interface", default=None)

    @property
    def time_taken(self) -> int | None:
        if self.time_taken_src.isdigit():
            return int(self.time_taken_src)
        return None


class HyperlinkObject(msgspec.Struct):
    url: str = msgspec.field(name="_url")
    ref: str
    id: str | int | None = None
    type: str | None = None


class TransactionObjectFromAPI(msgspec.Struct):
    type: TransactionTypeEnum = msgspec.field(name="Type")
    created: datetime.datetime = msgspec.field(name="Created")
    time_taken_src: str = msgspec.field(name="TimeTaken")
    id: int
    object: GenericObjStruct = msgspec.field(name="Object")
    hyperlinks: list[HyperlinkObject] = msgspec.field(name="_hyperlinks")
    creator: UserObjStruct = msgspec.field(name="Creator")
    old_value: GenericObjStruct | str | None = msgspec.field(name="OldValue", default=None)
    new_value: GenericObjStruct | str | None = msgspec.field(name="NewValue", default=None)
    field: GenericObjStruct | str | None = msgspec.field(name="Field", default=None)

    @property
    def time_taken(self) -> int | None:
        if self.time_taken_src.isdigit():
            return int(self.time_taken_src)
        return None


class AttachmentObjectFromAPI(msgspec.Struct):
    headers: str = msgspec.field(name="Headers")
    created: datetime.datetime = msgspec.field(name="Created")
    id: int
    content_type: str = msgspec.field(name="ContentType")
    creator: UserObjStruct = msgspec.field(name="Creator")
    transaction_id: GenericObjStruct = msgspec.field(name="TransactionId")
    message_id: str = msgspec.field(name="MessageId")
    hyperlinks: list[HyperlinkObject] = msgspec.field(name="_hyperlinks")
    subject: str = msgspec.field(name="Subject")
    parent: str | GenericObjStruct = msgspec.field(name="Parent")
    content: str | None = msgspec.field(name="Content", default=None)
    filename: str | None = msgspec.field(name="Filename", default=None)


class TicketData(msgspec.Struct):
    transaction: TransactionStruct
    transaction_from_api: TransactionObjectFromAPI
    attachments: list[AttachmentObjectFromAPI]
    body: str
    headers: Message


class TicketObjectFromAPI(TicketObjStruct):
    hyperlinks: list[HyperlinkObject] = msgspec.field(name="_hyperlinks", default_factory=list)


class CatalogObjectStruct(GenericObjStruct): ...


class AssetObjectFromAPI(msgspec.Struct):
    last_updated_by: UserObjStruct = msgspec.field(name="LastUpdatedBy")
    last_updated: str = msgspec.field(name="LastUpdated")
    catalog: CatalogObjectStruct = msgspec.field(name="Catalog")
    name: str = msgspec.field(name="Name")
    created: str = msgspec.field(name="Created")
    status: str = msgspec.field(name="Status")
    description: str = msgspec.field(name="Description")
    owner: UserObjStruct = msgspec.field(name="Owner")
    id: int = msgspec.field(name="id")
    creator: UserObjStruct = msgspec.field(name="Creator")
    hyperlinks: list[HyperlinkObject] = msgspec.field(name="_hyperlinks")
    custom_fields: list[CustomFieldStruct] = msgspec.field(name="CustomFields")
    held_by: list[UserObjStruct] = msgspec.field(name="HeldBy")
    contact: list[UserObjStruct] = msgspec.field(name="Contact")


class CatalogObjectFromAPI(msgspec.Struct):
    contact: list[UserObjStruct] = msgspec.field(name="Contact")
    description: str = msgspec.field(name="Description")
    hyperlinks: list[HyperlinkObject] = msgspec.field(name="_hyperlinks")
    name: str = msgspec.field(name="Name")
    lifecycle: str = msgspec.field(name="Lifecycle")
    created: str = msgspec.field(name="Created")
    disabled: str = msgspec.field(name="Disabled")
    last_updated: str = msgspec.field(name="LastUpdated")
    last_updated_by: UserObjStruct = msgspec.field(name="LastUpdatedBy")
    held_by: list[UserObjStruct] = msgspec.field(name="HeldBy")
    id: int = msgspec.field(name="id")
    creator: UserObjStruct = msgspec.field(name="Creator")


class AssetData(msgspec.Struct):
    catalog: str
    name: str
    status: str
    description: str
    id: int
    hyperlinks: list[HyperlinkObject]
    custom_fields: list[CustomFieldStruct]
