"""
Worktable GraphQL Types.

Defines GraphQL types for table definitions, columns, records, etc.
"""
import strawberry
from strawberry import auto
from typing import Optional, List, Any
from datetime import datetime
from uuid import UUID
from enum import Enum

from apps.services.worktable.models import (
    TableDefinition,
    TableColumn,
    TableRecord,
    SavedFilter,
    CustomView,
    RecordAuditLog,
    FieldType,
    RecordStatus,
)


# ============================================================================
# Enums
# ============================================================================

@strawberry.enum
class FieldTypeEnum(Enum):
    """Field type enumeration."""
    TEXT = "text"
    NUMBER = "number"
    DECIMAL = "decimal"
    DATE = "date"
    DATETIME = "datetime"
    BOOLEAN = "boolean"
    SELECT = "select"
    MULTI_SELECT = "multi_select"
    RELATION = "relation"
    FILE = "file"
    IMAGE = "image"
    FORMULA = "formula"
    ROLLUP = "rollup"
    LOOKUP = "lookup"
    USER = "user"
    EMAIL = "email"
    URL = "url"
    PHONE = "phone"
    JSON = "json"


@strawberry.enum
class RecordStatusEnum(Enum):
    """Record status enumeration."""
    DRAFT = "draft"
    PENDING = "pending"
    APPROVED = "approved"
    REJECTED = "rejected"
    ARCHIVED = "archived"


# ============================================================================
# Input Types
# ============================================================================

@strawberry.input
class ColumnInput:
    """Input type for creating/updating columns."""
    slug: str
    name: str
    field_type: FieldTypeEnum
    config: Optional[strawberry.scalars.JSON] = None
    validation: Optional[strawberry.scalars.JSON] = None
    default_value: Optional[str] = None
    order: Optional[int] = None
    is_required: bool = False
    is_unique: bool = False
    is_searchable: bool = True
    is_sortable: bool = True
    is_filterable: bool = True


@strawberry.input
class RecordInput:
    """Input type for creating/updating records."""
    data: strawberry.scalars.JSON
    status: Optional[RecordStatusEnum] = None


@strawberry.input
class FilterConditionInput:
    """Input type for filter conditions."""
    field: str
    operator: str  # eq, ne, gt, gte, lt, lte, contains, etc.
    value: strawberry.scalars.JSON


@strawberry.input
class SortInput:
    """Input type for sorting."""
    field: str
    order: str = "asc"  # asc, desc


@strawberry.input
class RecordFilterInput:
    """Input type for filtering records."""
    conditions: Optional[List[FilterConditionInput]] = None
    search: Optional[str] = None
    status: Optional[RecordStatusEnum] = None
    owner_id: Optional[int] = None


# ============================================================================
# Object Types
# ============================================================================

@strawberry.type
class TableColumnType:
    """GraphQL type for table columns."""
    id: UUID
    slug: str
    name: str
    field_type: str
    config: strawberry.scalars.JSON
    validation: strawberry.scalars.JSON
    default_value: Optional[str]
    order: int
    is_required: bool
    is_unique: bool
    is_searchable: bool
    is_sortable: bool
    is_filterable: bool
    created_at: datetime
    updated_at: datetime
    
    @classmethod
    def from_model(cls, obj: TableColumn) -> "TableColumnType":
        return cls(
            id=obj.id,
            slug=obj.slug,
            name=obj.name,
            field_type=obj.field_type,
            config=obj.config,
            validation=obj.validation,
            default_value=obj.default_value,
            order=obj.order,
            is_required=obj.is_required,
            is_unique=obj.is_unique,
            is_searchable=obj.is_searchable,
            is_sortable=obj.is_sortable,
            is_filterable=obj.is_filterable,
            created_at=obj.created_at,
            updated_at=obj.updated_at,
        )


@strawberry.type
class TableDefinitionType:
    """GraphQL type for table definitions."""
    id: UUID
    slug: str
    name: str
    description: Optional[str]
    icon: Optional[str]
    is_active: bool
    order: int
    enable_audit: bool
    settings: strawberry.scalars.JSON
    created_at: datetime
    updated_at: datetime
    columns: List[TableColumnType]
    record_count: int
    
    @classmethod
    def from_model(cls, obj: TableDefinition) -> "TableDefinitionType":
        return cls(
            id=obj.id,
            slug=obj.slug,
            name=obj.name,
            description=obj.description,
            icon=obj.icon,
            is_active=obj.is_active,
            order=obj.order,
            enable_audit=obj.enable_audit,
            settings=obj.settings,
            created_at=obj.created_at,
            updated_at=obj.updated_at,
            columns=[TableColumnType.from_model(c) for c in obj.columns.all()],
            record_count=obj.record_count,
        )


@strawberry.type
class OwnerType:
    """GraphQL type for record owner."""
    id: int
    email: str
    full_name: str


@strawberry.type
class TableRecordType:
    """GraphQL type for table records."""
    id: UUID
    table_id: UUID
    data: strawberry.scalars.JSON
    status: str
    version: int
    is_deleted: bool
    deleted_at: Optional[datetime]
    created_at: datetime
    updated_at: datetime
    owner: Optional[OwnerType]
    
    @classmethod
    def from_model(cls, obj: TableRecord) -> "TableRecordType":
        owner = None
        if obj.owner:
            owner = OwnerType(
                id=obj.owner.id,
                email=obj.owner.email,
                full_name=obj.owner.get_full_name() or obj.owner.email,
            )
        return cls(
            id=obj.id,
            table_id=obj.table_id,
            data=obj.data,
            status=obj.status,
            version=obj.version,
            is_deleted=obj.is_deleted,
            deleted_at=obj.deleted_at,
            created_at=obj.created_at,
            updated_at=obj.updated_at,
            owner=owner,
        )


@strawberry.type
class SavedFilterType:
    """GraphQL type for saved filters."""
    id: UUID
    name: str
    filters: strawberry.scalars.JSON
    is_default: bool
    is_shared: bool
    order: int
    created_at: datetime
    
    @classmethod
    def from_model(cls, obj: SavedFilter) -> "SavedFilterType":
        return cls(
            id=obj.id,
            name=obj.name,
            filters=obj.filters,
            is_default=obj.is_default,
            is_shared=obj.is_shared,
            order=obj.order,
            created_at=obj.created_at,
        )


@strawberry.type
class CustomViewType:
    """GraphQL type for custom views."""
    id: UUID
    name: str
    columns: strawberry.scalars.JSON
    sort: strawberry.scalars.JSON
    filters: strawberry.scalars.JSON
    is_default: bool
    is_shared: bool
    order: int
    created_at: datetime
    
    @classmethod
    def from_model(cls, obj: CustomView) -> "CustomViewType":
        return cls(
            id=obj.id,
            name=obj.name,
            columns=obj.columns,
            sort=obj.sort,
            filters=obj.filters,
            is_default=obj.is_default,
            is_shared=obj.is_shared,
            order=obj.order,
            created_at=obj.created_at,
        )


@strawberry.type
class AuditLogType:
    """GraphQL type for audit logs."""
    id: UUID
    record_id: Optional[UUID]
    user_id: Optional[int]
    user_name: Optional[str]
    action: str
    changes: strawberry.scalars.JSON
    metadata: strawberry.scalars.JSON
    ip_address: Optional[str]
    created_at: datetime
    
    @classmethod
    def from_model(cls, obj: RecordAuditLog) -> "AuditLogType":
        user_name = None
        if obj.user:
            user_name = obj.user.get_full_name() or obj.user.email
        return cls(
            id=obj.id,
            record_id=obj.record_id,
            user_id=obj.user_id,
            user_name=user_name,
            action=obj.action,
            changes=obj.changes,
            metadata=obj.metadata,
            ip_address=obj.ip_address,
            created_at=obj.created_at,
        )


# ============================================================================
# Pagination Types
# ============================================================================

@strawberry.type
class PageInfo:
    """Pagination info type."""
    has_next_page: bool
    has_previous_page: bool
    total_count: int
    page: int
    page_size: int
    total_pages: int


@strawberry.type
class TableRecordConnection:
    """Paginated list of records."""
    page_info: PageInfo
    nodes: List[TableRecordType]


@strawberry.type
class TableDefinitionConnection:
    """Paginated list of tables."""
    page_info: PageInfo
    nodes: List[TableDefinitionType]


# ============================================================================
# Result Types
# ============================================================================

@strawberry.type
class BulkOperationResult:
    """Result of bulk operations."""
    success_count: int
    error_count: int
    errors: Optional[List[strawberry.scalars.JSON]]


@strawberry.type
class MutationResult:
    """Generic mutation result."""
    success: bool
    message: Optional[str]
    errors: Optional[List[str]]
