"""
Document Tools

Tools for working with documents in SignNow.
"""

from typing import Literal

from signnow_client import SignNowAPIClient
from signnow_client.models.document_groups import (
    GetDocumentGroupTemplateResponse,
    GetDocumentGroupV2Response,
)
from signnow_client.models.templates_and_documents import (
    DocumentResponse,
)

import time

from .models import (
    DocumentField,
    DocumentGroup,
    DocumentGroupDocument,
    SimplifiedInvite,
    UpdateDocumentFields,
    UpdateDocumentFieldsResponse,
    UpdateDocumentFieldsResult,
    UploadDocumentResponse,
)


def _upload_document(file_content: bytes, filename: str, check_fields: bool, token: str, client: SignNowAPIClient) -> UploadDocumentResponse:
    """
    Upload a document to SignNow.

    Args:
        file_content: Document file content as bytes
        filename: Name of the file to upload
        check_fields: Whether to check for fields in the document
        token: Access token for authentication
        client: SignNow API client instance

    Returns:
        UploadDocumentResponse with uploaded document ID
    """

    # Upload document using the client
    response = client.upload_document(token=token, file_content=file_content, filename=filename, check_fields=check_fields)

    return UploadDocumentResponse(document_id=response.id, filename=filename, check_fields=check_fields)


def _get_full_document(client: SignNowAPIClient, token: str, document_id: str, document_data: DocumentResponse) -> DocumentGroupDocument:
    """
    Get full document information including field values.

    This function retrieves a document with all its metadata and field values.
    The basic information (id, name, roles) comes from the document endpoint,
    while field values are retrieved separately using get_document_fields.

    Args:
        client: SignNow API client instance
        token: Access token for authentication
        document_id: ID of the document to retrieve
        document_data: Pre-fetched document data to avoid duplicate API calls

    Returns:
        DocumentGroupDocument with complete document information including field values
    """

    # Use provided document data
    document_response = document_data

    # Create DocumentField objects with values
    document_fields = []

    for field in document_response.fields:
        if field.type == "text":
            document_fields.append(
                DocumentField(
                    id=field.id,
                    type=field.type,
                    role_id=field.role,  # Using role name as role_id for consistency
                    value=field.json_attributes.prefilled_text or "",
                    name=field.json_attributes.name,
                )
            )

    return DocumentGroupDocument(id=document_response.id, name=document_response.document_name, roles=[role.name for role in document_response.roles], fields=document_fields)


def _get_full_document_group(client: SignNowAPIClient, token: str, group_data: GetDocumentGroupV2Response) -> DocumentGroup:
    """
    Get full document group information including all documents with their field values.

    This function retrieves a document group using v2 API and for each document in the group,
    gets the complete document information including field values.

    Args:
        client: SignNow API client instance
        token: Access token for authentication
        document_group_id: ID of the document group to retrieve
        group_data: Pre-fetched group data to avoid duplicate API calls

    Returns:
        DocumentGroup with complete information including all documents with field values
    """

    # Use provided group data
    group_data = group_data.data

    # Get full document information for each document in the group
    full_documents = []
    all_field_invites = []
    for doc in group_data.documents:
        # Collect field_invites from each document
        if doc.field_invites:
            all_field_invites.extend(doc.field_invites)
        # Get document data first
        document_data = client.get_document(token, doc.id)
        full_doc = _get_full_document(client=client, token=token, document_id=doc.id, document_data=document_data)
        full_documents.append(full_doc)

    # Create invite from group data and field_invites
    now = int(time.time())
    invite = SimplifiedInvite.from_document_group_v2(
        invite_id=group_data.invite_id,
        raw_status=group_data.state,
        field_invites=all_field_invites if all_field_invites else None,
        now=now,
    )

    # Create DocumentGroup with full document information
    return DocumentGroup(
        last_updated=group_data.created,  # Use created timestamp as last_updated
        entity_id=group_data.id,
        group_name=group_data.name,
        entity_type="document_group",
        invite=invite,
        documents=full_documents,
    )


def _get_full_template_group(client: SignNowAPIClient, token: str, template_group_data: GetDocumentGroupTemplateResponse) -> DocumentGroup:
    """
    Get full template group information including all templates with their field values.

    This function retrieves a template group and for each template in the group,
    gets the complete template information including field values.

    Args:
        client: SignNow API client instance
        token: Access token for authentication
        template_group_data: Pre-fetched template group data to avoid duplicate API calls

    Returns:
        DocumentGroup with complete information including all templates with field values
    """

    # Get full document information for each template in the group
    full_documents = []
    for template in template_group_data.templates:
        # Get template data as document (templates are documents in SignNow)
        document_data = client.get_document(token, template.id)
        full_doc = _get_full_document(client=client, token=token, document_id=template.id, document_data=document_data)
        full_documents.append(full_doc)

    # Create DocumentGroup with full template information
    return DocumentGroup(
        last_updated=0,  # Not available in template group response
        entity_id=template_group_data.id,
        group_name=template_group_data.group_name,
        entity_type="template_group",
        invite=None,  # Not applicable for template groups
        documents=full_documents,
    )


def _get_document(client: SignNowAPIClient, token: str, entity_id: str, entity_type: Literal["document", "document_group", "template", "template_group"] | None = None) -> DocumentGroup:
    """
    Get document or document group information with full field values.

    This function determines the entity type if not provided and returns
    a DocumentGroup with complete information including field values.

    Args:
        client: SignNow API client instance
        token: Access token for authentication
        entity_id: ID of the document or document group
        entity_type: Type of entity: 'document', 'template', 'template_group' or 'document_group' (optional)

    Returns:
        DocumentGroup with complete information including field values

    Raises:
        ValueError: If entity not found as either document or document group
    """

    # Determine entity type if not provided and get entity data
    document_data = None
    template_group_data = None
    group_data = None

    if not entity_type:
        # Try to determine entity type by attempting to get document first
        try:
            # Try to get document - if successful, it's a document
            document_data = client.get_document(token, entity_id)
            entity_type = "document"
        except Exception:
            # If document not found, try document group
            try:
                # Try to get document group - if successful, it's a document group
                group_data = client.get_document_group_v2(token, entity_id)
                entity_type = "document_group"
            except Exception:
                # If document group not found, try template group
                try:
                    # Try to get template group - if successful, it's a template group
                    template_group_data = client.get_document_group_template(token, entity_id)
                    entity_type = "template_group"
                except Exception:
                    raise ValueError(f"Entity with ID {entity_id} not found as either document, template, template group or document group")
    else:
        # Entity type is provided, get the entity data
        if entity_type == "document_group":
            group_data = client.get_document_group_v2(token, entity_id)
        elif entity_type == "template":
            document_data = client.get_document(token, entity_id)
        elif entity_type == "template_group":
            template_group_data = client.get_document_group_template(token, entity_id)
        else:  # entity_type == "document"
            document_data = client.get_document(token, entity_id)

    # Get the appropriate data based on determined or provided entity type
    if entity_type == "document_group":
        return _get_full_document_group(client, token, group_data)
    elif entity_type == "template_group":
        return _get_full_template_group(client, token, template_group_data)
    else:  # entity_type == "document" or "template"
        return _get_single_document_as_group(client, token, entity_id, document_data)


def _get_single_document_as_group(client: SignNowAPIClient, token: str, document_id: str, document_data: DocumentResponse) -> DocumentGroup:
    """
    Get a single document and return it as a DocumentGroup with one document.

    Args:
        client: SignNow API client instance
        token: Access token for authentication
        document_id: ID of the document to retrieve
        document_data: Pre-fetched document data to avoid duplicate API calls

    Returns:
        DocumentGroup containing the single document with full field values
    """

    # Get full document information
    full_document = _get_full_document(client, token, document_id, document_data)

    # Create invite from field_invites
    now = int(time.time())
    invite = SimplifiedInvite.from_document_field_invites(document_data.field_invites, now)

    # Create DocumentGroup with single document
    return DocumentGroup(
        last_updated=0,  # Not available for single documents
        entity_id=document_id,
        group_name=full_document.name,
        entity_type="document",
        invite=invite,
        documents=[full_document],
    )


def _update_document_fields(client: SignNowAPIClient, token: str, update_requests: list[UpdateDocumentFields]) -> UpdateDocumentFieldsResponse:
    """
    Update fields for multiple documents.

    This function updates text fields in multiple documents using the SignNow API.
    Only text fields can be updated using the prefill_text_fields endpoint.

    Args:
        client: SignNow API client instance
        token: Access token for authentication
        update_requests: List of UpdateDocumentFields with document IDs and fields to update

    Returns:
        UpdateDocumentFieldsResponse with results for each document update
    """

    results = []

    for update_request in update_requests:
        try:
            # Convert FieldToUpdate to PrefillTextField format
            prefill_fields = []
            for field in update_request.fields:
                prefill_fields.append({"field_name": field.name, "prefilled_text": field.value})

            # Create PrefillTextFieldsRequest
            from signnow_client.models.templates_and_documents import (
                PrefillTextField,
                PrefillTextFieldsRequest,
            )

            prefill_request = PrefillTextFieldsRequest(fields=[PrefillTextField(field_name=field.name, prefilled_text=field.value) for field in update_request.fields])

            # Update fields using the client
            success = client.prefill_text_fields(token=token, document_id=update_request.document_id, request_data=prefill_request)

            results.append(UpdateDocumentFieldsResult(document_id=update_request.document_id, updated=success, reason=None))  # No reason needed for success

        except Exception as e:
            # Log error and mark as failed
            error_message = str(e)
            results.append(UpdateDocumentFieldsResult(document_id=update_request.document_id, updated=False, reason=error_message))

    return UpdateDocumentFieldsResponse(results=results)
