"""
SignNow API Data Models - Document Groups and Template Groups

Pydantic models for SignNow API responses and requests related to document groups and template groups.
"""

from typing import Any

from typing_extensions import Self

from pydantic import BaseModel, EmailStr, Field, HttpUrl


class DocumentGroupTemplate(BaseModel):
    """Single item of the `document_group_templates` array."""

    folder_id: str | None = Field(None, description="Folder ID, if the group is stored in a folder")
    last_updated: int = Field(..., description="Unix timestamp of the last update")
    template_group_id: str = Field(..., description="Document-group template ID")
    template_group_name: str = Field(..., description="Name of the template group")
    owner_email: EmailStr = Field(..., description="Owner of the template group")
    templates: list[dict[str, Any]] = Field(..., description="Templates in this group")
    is_prepared: bool = Field(..., description="Whether the group is ready for sending")


class DocumentGroupTemplatesResponse(BaseModel):
    """Full JSON response from `/user/documentgroup/templates`."""

    document_group_templates: list[DocumentGroupTemplate]
    document_group_template_total_count: int = Field(..., description="Total number of template groups in the response")


class DocumentGroupDocument(BaseModel):
    """Document information within a document group."""

    id: str = Field(..., description="Document ID")
    document_name: str | None = Field(None, description="Document name")
    thumbnail: dict[str, str] = Field(..., description="Document thumbnails")
    roles: list[str] = Field(..., description="Roles defined for this document")


class DocumentGroup(BaseModel):
    """Single document group from the `/user/documentgroups` endpoint."""

    last_updated: int = Field(..., description="Unix timestamp of the last update")
    group_id: str = Field(..., description="Document group ID")
    group_name: str = Field(..., description="Name of the document group")
    invite_id: str | None = Field(None, description="Invite ID for this group")
    invite_status: str | None = Field(None, description="Status of the invite (e.g., 'pending')")
    documents: list[DocumentGroupDocument] = Field(..., description="List of documents in this group")


class DocumentGroupsResponse(BaseModel):
    """Full JSON response from `/user/documentgroups`."""

    document_groups: list[DocumentGroup]
    document_group_total_count: int = Field(..., description="Total number of document groups")


class CreateDocumentGroupRequest(BaseModel):
    """Request model for creating document group."""

    document_ids: list[str] = Field(..., description="Array of document IDs to group together")
    group_name: str = Field(..., description="Name for the document group")


class CreateDocumentGroupResponse(BaseModel):
    """Response model for creating document group."""

    id: str = Field(..., description="ID of the created document group")


class CreateDocumentGroupTemplateRequest(BaseModel):
    """Request model for creating document group template."""

    name: str = Field(..., description="Document group template name")
    folder_id: str | None = Field(None, description="ID of the templates folder")


class CreateDocumentGroupTemplateResponse(BaseModel):
    """Response model for creating document group template."""

    data: dict[str, str] = Field(..., description="Document group template ID")


class CreateDocumentGroupTemplateFromGroupRequest(BaseModel):
    """Request model for creating document group template from document group."""

    name: str = Field(..., description="Name for the new document group template")
    folder_id: str | None = Field(None, description="Folder where to save the template (must be Templates folder or subfolder)")


class AddTemplateToDocumentGroupTemplateRequest(BaseModel):
    """Request model for adding template to document group template."""

    document_id: str | None = Field(None, description="ID of the document to add")
    template_id: str | None = Field(None, description="ID of the template to add")


class AddTemplateToDocumentGroupTemplateResponse(BaseModel):
    """Response model for adding template to document group template."""

    data: dict[str, str] = Field(..., description="ID of the added template")


class CreateDocumentGroupFromTemplateRequest(BaseModel):
    """Request model for creating document group from template."""

    group_name: str = Field(..., description="Name of the document group")
    client_timestamp: str | None = Field(None, description="Timestamp of client")
    folder_id: str | None = Field(None, description="ID of the folder")


class DocumentGroupTemplateDocument(BaseModel):
    """Document in document group template."""

    id: str = Field(..., description="Document ID")
    role: str = Field(..., description="Recipient's role name")
    action: str = Field(..., description="Allowed action: 'view', 'sign', 'approve'")


class DocumentGroupTemplateRecipientReminder(BaseModel):
    """Reminder settings for document group template recipient."""

    remind_after: int | None = Field(None, description="Send reminder after specified days")
    remind_before: int | None = Field(None, description="Send reminder before expiration")
    remind_repeat: int | None = Field(None, description="Send reminder every specified days")


class DocumentGroupTemplateRecipientAuthentication(BaseModel):
    """Authentication settings for document group template recipient."""

    type: str = Field(..., description="Authentication type: 'phone' or 'password'")
    value: str | None = Field(None, description="Password value for password authentication")
    phone: str | None = Field(None, description="Phone number for phone authentication")
    method: str | None = Field(None, description="Method for phone: 'sms' or 'phone_call'")
    sms_message: str | None = Field(None, description="Custom SMS message with {password} placeholder")


class DocumentGroupTemplateRecipientAttributes(BaseModel):
    """Attributes for document group template recipient."""

    message: str | None = Field(None, description="Invite email message")
    subject: str | None = Field(None, description="Invite email subject")
    expiration_days: int | None = Field(None, description="Days until invite expires (3-180)")
    reminder: DocumentGroupTemplateRecipientReminder | None = Field(None, description="Reminder email settings")
    allow_forwarding: bool | None = Field(None, description="Allow recipients to reassign invite")
    i_am_recipient: bool | None = Field(None, description="Document sender is also recipient")
    show_decline_button: bool | None = Field(None, description="Show decline button on signature fields")
    redirect_uri: str | None = Field(None, description="URL after recipient completes document")
    redirect_target: str | None = Field(None, description="Redirect target: 'blank' or 'self'")
    decline_redirect_uri: str | None = Field(None, description="URL after recipient declines document")
    close_redirect_uri: str | None = Field(None, description="URL after save progress or close")

    def model_dump(self: Self, **kwargs: Any) -> dict[str, Any]:  # noqa: ANN401
        """Override model_dump to exclude redirect_target if redirect_uri is not provided."""
        data = super().model_dump(**kwargs)
        if (not self.redirect_uri or not self.redirect_uri.strip()) and "redirect_target" in data:
            del data["redirect_target"]
        return data


class DocumentGroupTemplateRecipient(BaseModel):
    """Recipient in document group template."""

    name: str = Field(..., description="Recipient's name")
    email: str | None = Field(None, description="Recipient's email address")
    order: int = Field(..., description="Recipient's order of signing")
    documents: list[DocumentGroupTemplateDocument] = Field(..., description="List of documents and roles")
    attributes: DocumentGroupTemplateRecipientAttributes | None = Field(None, description="Recipient attributes")


class UnmappedDocument(BaseModel):
    """Unmapped document in document group template."""

    id: str = Field(..., description="Document ID")
    role: str = Field(..., description="Recipient's role name")
    action: str = Field(..., description="Allowed action")


class AllowedUnmappedSignDocument(BaseModel):
    """Allowed unmapped sign document."""

    id: str = Field(..., description="Document ID")
    role: str = Field(..., description="Recipient's role name")
    recipient: str = Field(..., description="Recipient's name")


class GetDocumentGroupTemplateRecipientsResponse(BaseModel):
    """Response model for getting document group template recipients."""

    data: dict[str, Any] = Field(..., description="Recipients data including recipients, unmapped documents, and cc")


class EditDocumentGroupTemplateRecipientsRequest(BaseModel):
    """Request model for editing document group template recipients."""

    recipients: list[DocumentGroupTemplateRecipient] = Field(..., description="List of recipients")
    unmapped_documents: list[UnmappedDocument] | None = Field(None, description="List of unmapped documents")
    allowed_unmapped_sign_documents: list[AllowedUnmappedSignDocument] | None = Field(None, description="List of allowed unmapped sign documents")
    cc: list[str] | None = Field(None, description="List of cc recipient emails (max 100)")


class CreateDocumentGroupFromTemplateResponse(BaseModel):
    """Response model for creating document group from template."""

    data: dict[str, Any] = Field(..., description="Created document group data")


# Embedded models for document groups
class CreateDocumentGroupEmbeddedEditorRequest(BaseModel):
    """Request model for creating document group embedded editor link."""

    redirect_uri: str | None = Field(None, description="Link that opens after editing the document group")
    link_expiration: int | None = Field(15, description="Link expiration in minutes (default: 15, max: 43200 for Admin users)")
    redirect_target: str | None = Field("self", description="Redirect target: 'blank' (new tab) or 'self' (same tab)")

    def model_dump(self: Self, **kwargs: Any) -> dict[str, Any]:  # noqa: ANN401
        """Override model_dump to exclude redirect_target if redirect_uri is not provided."""
        data = super().model_dump(**kwargs)
        if (not self.redirect_uri or not self.redirect_uri.strip()) and "redirect_target" in data:
            del data["redirect_target"]
        return data


class CreateDocumentGroupEmbeddedSendingRequest(BaseModel):
    """Request model for creating document group embedded sending link."""

    redirect_uri: str | None = Field(None, description="Page that opens after embedded sending has been set up")
    redirect_target: str | None = Field("self", description="Redirect target: 'blank' (new tab) or 'self' (same tab)")
    link_expiration: int | None = Field(15, description="Link expiration in minutes (15-45, max: 43200 for Admin users)")
    type: str | None = Field("manage", description="Sending step: 'manage' (Add documents), 'edit' (editor), 'send-invite' (Send Invite page)")

    def model_dump(self: Self, **kwargs: Any) -> dict[str, Any]:  # noqa: ANN401
        """Override model_dump to exclude redirect_target if redirect_uri is not provided."""
        data = super().model_dump(**kwargs)
        if (not self.redirect_uri or not self.redirect_uri.strip()) and "redirect_target" in data:
            del data["redirect_target"]
        return data


class GetDocumentGroupResponse(BaseModel):
    """Response model for getting a single document group."""

    id: str = Field(..., description="Document group ID")
    group_name: str = Field(..., description="Name of the document group")
    invite_id: str | None = Field(None, description="Invite ID for this group")
    documents: list[DocumentGroupDocument] = Field(..., description="List of documents in this group")
    originator_organization_settings: list[dict[str, Any]] = Field(..., description="Organization settings for the originator")


# V2 Document Group models
class DocumentGroupV2Owner(BaseModel):
    """Owner information in v2 document group response."""

    id: str = Field(..., description="Owner ID")
    email: str = Field(..., description="Owner email")
    organization: dict[str, str] = Field(..., description="Organization info with ID")


class DocumentGroupV2Thumbnail(BaseModel):
    """Thumbnail URLs for document in v2 response."""

    small: str = Field(..., description="Small thumbnail URL")
    medium: str = Field(..., description="Medium thumbnail URL")
    large: str = Field(..., description="Large thumbnail URL")


class DocumentGroupV2EmailStatus(BaseModel):
    """Email status for field invite in v2 response."""

    status: str = Field(..., description="Email status (e.g., 'sent')")
    created_at: int = Field(..., description="Unix timestamp when status was created")
    last_reaction_at: int = Field(..., description="Unix timestamp of last reaction")


class DocumentGroupV2EmailGroup(BaseModel):
    """Email group information in v2 response."""

    id: str | None = Field(None, description="Email group ID")
    name: str | None = Field(None, description="Email group name")


class DocumentGroupV2FieldInvite(BaseModel):
    """Field invite information in v2 response."""

    id: str = Field(..., description="Field invite ID")
    created: int = Field(..., description="Unix timestamp when invite was created")
    updated: int = Field(..., description="Unix timestamp when invite was updated")
    status: str = Field(..., description="Invite status (e.g., 'pending')")
    expiration_time: int | None = Field(None, description="Unix timestamp when invite expires")
    expiration_days: int | None = Field(None, description="Number of days until expiration")
    signer_email: str = Field(..., description="Email of the signer")
    password_protected: str = Field(..., description="Whether invite is password protected ('1' or '0')")
    email_group: DocumentGroupV2EmailGroup | None = Field(None, description="Email group if used")
    email_statuses: list[DocumentGroupV2EmailStatus] = Field(..., description="List of email statuses")


class DocumentGroupV2DocumentOwner(BaseModel):
    """Document owner information in v2 response."""

    id: str = Field(..., description="Document owner ID")
    email: str = Field(..., description="Document owner email")


class DocumentGroupV2Document(BaseModel):
    """Document information in v2 document group response."""

    roles: list[str] = Field(..., description="List of roles for this document")
    document_name: str = Field(..., description="Name of the document")
    id: str = Field(..., description="Document ID")
    updated: int = Field(..., description="Unix timestamp when document was last updated")
    field_invites: list[DocumentGroupV2FieldInvite] = Field(..., description="List of field invites for this document")


class DocumentGroupV2FreeformInvite(BaseModel):
    """Freeform invite information in v2 response."""

    id: str | None = Field(None, description="Freeform invite ID")
    last_id: str | None = Field(None, description="Last freeform invite ID")


class DocumentGroupV2Data(BaseModel):
    """Document group data in v2 response."""

    id: str = Field(..., description="Document group ID")
    name: str = Field(..., description="Document group name")
    created: int = Field(..., description="Unix timestamp when group was created")
    invite_id: str | None = Field(None, description="Current invite ID")
    pending_step_id: str | None = Field(None, description="ID of the pending step")
    state: str = Field(..., description="Current state of the document group (e.g., 'pending')")
    last_invite_id: str | None = Field(None, description="ID of the last invite")
    documents: list[DocumentGroupV2Document] = Field(..., description="List of documents in the group")


class GetDocumentGroupV2Response(BaseModel):
    """Response model for getting a single document group using v2 endpoint."""

    data: DocumentGroupV2Data = Field(..., description="Document group data as returned by v2 endpoint")


class TemplateShortThumbnail(BaseModel):
    """Thumbnail information for template in document group template response."""

    large: HttpUrl = Field(..., description="Large thumbnail URL")


class TemplateShort(BaseModel):
    """Short template information in document group template response."""

    id: str = Field(..., description="Template ID (40-character HEX)")
    template_name: str = Field(..., description="Template name")
    thumbnail: TemplateShortThumbnail = Field(..., description="Template thumbnail with large URL")
    roles: list[str] = Field(..., description="Roles defined for this template")


class GetDocumentGroupTemplateResponse(BaseModel):
    """Response model for getting a single document group template by ID."""

    id: str = Field(..., description="Document group template ID")
    group_name: str = Field(..., description="Name of the template group")
    templates: list[TemplateShort] = Field(..., description="List of templates in this group")
