"""
Worktable GraphQL Mutations.

Defines GraphQL mutation resolvers for CRUD operations.
"""
import strawberry
from strawberry.types import Info
from typing import Optional, List
from uuid import UUID

from apps.core.tenant.middleware import get_current_tenant
from apps.services.worktable.models import (
    TableDefinition,
    TableColumn,
    TableRecord,
    SavedFilter,
    CustomView,
    RecordStatus,
)
from apps.services.worktable.services import (
    TableService,
    ColumnService,
    RecordService,
    ViewService,
)

from .types import (
    TableDefinitionType,
    TableColumnType,
    TableRecordType,
    SavedFilterType,
    CustomViewType,
    ColumnInput,
    RecordInput,
    BulkOperationResult,
    MutationResult,
)
from .queries import get_current_user, get_tenant_from_context


# ============================================================================
# Table Mutations
# ============================================================================

@strawberry.input
class CreateTableInput:
    """Input for creating a table."""
    slug: str
    name: str
    description: Optional[str] = None
    icon: Optional[str] = None
    color: Optional[str] = None
    enable_audit: bool = True
    columns: Optional[List[ColumnInput]] = None


@strawberry.input
class UpdateTableInput:
    """Input for updating a table."""
    name: Optional[str] = None
    description: Optional[str] = None
    icon: Optional[str] = None
    color: Optional[str] = None
    is_active: Optional[bool] = None
    settings: Optional[strawberry.scalars.JSON] = None


@strawberry.type
class TableMutationResult:
    """Result of table mutations."""
    success: bool
    table: Optional[TableDefinitionType]
    errors: Optional[List[str]]


# ============================================================================
# Record Mutations
# ============================================================================

@strawberry.type
class RecordMutationResult:
    """Result of record mutations."""
    success: bool
    record: Optional[TableRecordType]
    errors: Optional[List[str]]


@strawberry.input
class CreateRecordInput:
    """Input for creating a record."""
    data: strawberry.scalars.JSON
    status: Optional[str] = None


@strawberry.input
class UpdateRecordInput:
    """Input for updating a record."""
    data: strawberry.scalars.JSON
    status: Optional[str] = None


@strawberry.input
class BulkDeleteInput:
    """Input for bulk delete."""
    record_ids: List[UUID]
    hard_delete: bool = False


# ============================================================================
# Filter/View Mutations
# ============================================================================

@strawberry.input
class CreateFilterInput:
    """Input for creating a saved filter."""
    name: str
    filters: strawberry.scalars.JSON
    is_default: bool = False
    is_shared: bool = False


@strawberry.input
class CreateViewInput:
    """Input for creating a custom view."""
    name: str
    columns: Optional[strawberry.scalars.JSON] = None
    sort: Optional[strawberry.scalars.JSON] = None
    filters: Optional[strawberry.scalars.JSON] = None
    is_default: bool = False
    is_shared: bool = False


# ============================================================================
# Mutation Type
# ============================================================================

@strawberry.type
class WorktableMutation:
    """Worktable GraphQL mutations."""
    
    # ========== Table Mutations ==========
    
    @strawberry.mutation
    def create_table(
        self,
        info: Info,
        input: CreateTableInput,
    ) -> TableMutationResult:
        """Create a new table definition."""
        tenant = get_tenant_from_context(info)
        if not tenant:
            return TableMutationResult(
                success=False,
                table=None,
                errors=["Tenant not found"],
            )
        
        try:
            # Check for duplicate slug
            if TableDefinition.objects.filter(tenant=tenant, slug=input.slug).exists():
                return TableMutationResult(
                    success=False,
                    table=None,
                    errors=[f"Table with slug '{input.slug}' already exists"],
                )
            
            # Create table
            table = TableDefinition.objects.create(
                tenant=tenant,
                slug=input.slug,
                name=input.name,
                description=input.description,
                icon=input.icon,
                color=input.color,
                enable_audit=input.enable_audit,
            )
            
            # Create columns if provided
            if input.columns:
                for i, col in enumerate(input.columns):
                    TableColumn.objects.create(
                        table=table,
                        slug=col.slug,
                        name=col.name,
                        field_type=col.field_type.value,
                        config=col.config or {},
                        validation=col.validation or {},
                        default_value=col.default_value,
                        order=col.order if col.order is not None else i,
                        is_required=col.is_required,
                        is_unique=col.is_unique,
                        is_searchable=col.is_searchable,
                        is_sortable=col.is_sortable,
                        is_filterable=col.is_filterable,
                    )
            
            return TableMutationResult(
                success=True,
                table=TableDefinitionType.from_model(table),
                errors=None,
            )
        except Exception as e:
            return TableMutationResult(
                success=False,
                table=None,
                errors=[str(e)],
            )
    
    @strawberry.mutation
    def update_table(
        self,
        info: Info,
        slug: str,
        input: UpdateTableInput,
    ) -> TableMutationResult:
        """Update a table definition."""
        tenant = get_tenant_from_context(info)
        if not tenant:
            return TableMutationResult(
                success=False,
                table=None,
                errors=["Tenant not found"],
            )
        
        try:
            table = TableDefinition.objects.get(tenant=tenant, slug=slug)
            
            if input.name is not None:
                table.name = input.name
            if input.description is not None:
                table.description = input.description
            if input.icon is not None:
                table.icon = input.icon
            if input.color is not None:
                table.color = input.color
            if input.is_active is not None:
                table.is_active = input.is_active
            if input.settings is not None:
                table.settings = input.settings
            
            table.save()
            
            return TableMutationResult(
                success=True,
                table=TableDefinitionType.from_model(table),
                errors=None,
            )
        except TableDefinition.DoesNotExist:
            return TableMutationResult(
                success=False,
                table=None,
                errors=[f"Table '{slug}' not found"],
            )
        except Exception as e:
            return TableMutationResult(
                success=False,
                table=None,
                errors=[str(e)],
            )
    
    @strawberry.mutation
    def delete_table(
        self,
        info: Info,
        slug: str,
        hard_delete: bool = False,
    ) -> MutationResult:
        """Delete a table (soft or hard delete)."""
        tenant = get_tenant_from_context(info)
        if not tenant:
            return MutationResult(
                success=False,
                message=None,
                errors=["Tenant not found"],
            )
        
        try:
            table = TableDefinition.objects.get(tenant=tenant, slug=slug)
            TableService.delete_table(table, hard_delete=hard_delete)
            
            return MutationResult(
                success=True,
                message=f"Table '{slug}' deleted successfully",
                errors=None,
            )
        except TableDefinition.DoesNotExist:
            return MutationResult(
                success=False,
                message=None,
                errors=[f"Table '{slug}' not found"],
            )
        except Exception as e:
            return MutationResult(
                success=False,
                message=None,
                errors=[str(e)],
            )
    
    # ========== Column Mutations ==========
    
    @strawberry.mutation
    def add_column(
        self,
        info: Info,
        table_slug: str,
        input: ColumnInput,
    ) -> TableMutationResult:
        """Add a column to a table."""
        tenant = get_tenant_from_context(info)
        if not tenant:
            return TableMutationResult(
                success=False,
                table=None,
                errors=["Tenant not found"],
            )
        
        try:
            table = TableDefinition.objects.get(tenant=tenant, slug=table_slug)
            
            # Check for duplicate slug
            if table.columns.filter(slug=input.slug).exists():
                return TableMutationResult(
                    success=False,
                    table=None,
                    errors=[f"Column with slug '{input.slug}' already exists"],
                )
            
            # Get next order if not specified
            order = input.order
            if order is None:
                last_order = table.columns.order_by('-order').values_list('order', flat=True).first()
                order = (last_order or 0) + 1
            
            TableColumn.objects.create(
                table=table,
                slug=input.slug,
                name=input.name,
                field_type=input.field_type.value,
                config=input.config or {},
                validation=input.validation or {},
                default_value=input.default_value,
                order=order,
                is_required=input.is_required,
                is_unique=input.is_unique,
                is_searchable=input.is_searchable,
                is_sortable=input.is_sortable,
                is_filterable=input.is_filterable,
            )
            
            return TableMutationResult(
                success=True,
                table=TableDefinitionType.from_model(table),
                errors=None,
            )
        except TableDefinition.DoesNotExist:
            return TableMutationResult(
                success=False,
                table=None,
                errors=[f"Table '{table_slug}' not found"],
            )
        except Exception as e:
            return TableMutationResult(
                success=False,
                table=None,
                errors=[str(e)],
            )
    
    # ========== Record Mutations ==========
    
    @strawberry.mutation
    def create_record(
        self,
        info: Info,
        table_slug: str,
        input: CreateRecordInput,
    ) -> RecordMutationResult:
        """Create a new record."""
        tenant = get_tenant_from_context(info)
        user = get_current_user(info)
        if not tenant:
            return RecordMutationResult(
                success=False,
                record=None,
                errors=["Tenant not found"],
            )
        
        try:
            table = TableDefinition.objects.get(tenant=tenant, slug=table_slug)
            
            status = input.status or RecordStatus.DRAFT
            request = info.context.get("request")
            
            record = RecordService.create_record(
                table=table,
                data=input.data,
                owner=user,
                status=status,
                request=request,
            )
            
            return RecordMutationResult(
                success=True,
                record=TableRecordType.from_model(record),
                errors=None,
            )
        except TableDefinition.DoesNotExist:
            return RecordMutationResult(
                success=False,
                record=None,
                errors=[f"Table '{table_slug}' not found"],
            )
        except Exception as e:
            return RecordMutationResult(
                success=False,
                record=None,
                errors=[str(e)],
            )
    
    @strawberry.mutation
    def update_record(
        self,
        info: Info,
        table_slug: str,
        record_id: UUID,
        input: UpdateRecordInput,
    ) -> RecordMutationResult:
        """Update a record."""
        tenant = get_tenant_from_context(info)
        if not tenant:
            return RecordMutationResult(
                success=False,
                record=None,
                errors=["Tenant not found"],
            )
        
        try:
            table = TableDefinition.objects.get(tenant=tenant, slug=table_slug)
            record = TableRecord.objects.get(id=record_id, table=table, is_deleted=False)
            
            request = info.context.get("request")
            
            record = RecordService.update_record(
                record=record,
                data=input.data,
                partial=True,
                request=request,
            )
            
            if input.status:
                record.status = input.status
                record.save(update_fields=['status'])
            
            return RecordMutationResult(
                success=True,
                record=TableRecordType.from_model(record),
                errors=None,
            )
        except TableDefinition.DoesNotExist:
            return RecordMutationResult(
                success=False,
                record=None,
                errors=[f"Table '{table_slug}' not found"],
            )
        except TableRecord.DoesNotExist:
            return RecordMutationResult(
                success=False,
                record=None,
                errors=["Record not found"],
            )
        except Exception as e:
            return RecordMutationResult(
                success=False,
                record=None,
                errors=[str(e)],
            )
    
    @strawberry.mutation
    def delete_record(
        self,
        info: Info,
        table_slug: str,
        record_id: UUID,
        hard_delete: bool = False,
    ) -> MutationResult:
        """Delete a record."""
        tenant = get_tenant_from_context(info)
        if not tenant:
            return MutationResult(
                success=False,
                message=None,
                errors=["Tenant not found"],
            )
        
        try:
            table = TableDefinition.objects.get(tenant=tenant, slug=table_slug)
            record = TableRecord.objects.get(id=record_id, table=table)
            
            request = info.context.get("request")
            RecordService.delete_record(record, hard_delete=hard_delete, request=request)
            
            return MutationResult(
                success=True,
                message="Record deleted successfully",
                errors=None,
            )
        except (TableDefinition.DoesNotExist, TableRecord.DoesNotExist):
            return MutationResult(
                success=False,
                message=None,
                errors=["Record not found"],
            )
        except Exception as e:
            return MutationResult(
                success=False,
                message=None,
                errors=[str(e)],
            )
    
    @strawberry.mutation
    def bulk_delete_records(
        self,
        info: Info,
        table_slug: str,
        input: BulkDeleteInput,
    ) -> BulkOperationResult:
        """Bulk delete records."""
        tenant = get_tenant_from_context(info)
        user = get_current_user(info)
        if not tenant:
            return BulkOperationResult(
                success_count=0,
                error_count=0,
                errors=[{"message": "Tenant not found"}],
            )
        
        try:
            table = TableDefinition.objects.get(tenant=tenant, slug=table_slug)
            request = info.context.get("request")
            
            count = RecordService.bulk_delete(
                table=table,
                record_ids=input.record_ids,
                hard_delete=input.hard_delete,
                user=user,
                request=request,
            )
            
            return BulkOperationResult(
                success_count=count,
                error_count=len(input.record_ids) - count,
                errors=None,
            )
        except TableDefinition.DoesNotExist:
            return BulkOperationResult(
                success_count=0,
                error_count=len(input.record_ids),
                errors=[{"message": f"Table '{table_slug}' not found"}],
            )
        except Exception as e:
            return BulkOperationResult(
                success_count=0,
                error_count=len(input.record_ids),
                errors=[{"message": str(e)}],
            )
    
    # ========== Filter/View Mutations ==========
    
    @strawberry.mutation
    def save_filter(
        self,
        info: Info,
        table_slug: str,
        input: CreateFilterInput,
    ) -> MutationResult:
        """Save a filter configuration."""
        tenant = get_tenant_from_context(info)
        user = get_current_user(info)
        if not tenant or not user:
            return MutationResult(
                success=False,
                message=None,
                errors=["Authentication required"],
            )
        
        try:
            table = TableDefinition.objects.get(tenant=tenant, slug=table_slug)
            
            ViewService.save_filter(
                table=table,
                user=user,
                name=input.name,
                filter_config=input.filters,
                is_default=input.is_default,
                is_shared=input.is_shared,
            )
            
            return MutationResult(
                success=True,
                message="Filter saved successfully",
                errors=None,
            )
        except TableDefinition.DoesNotExist:
            return MutationResult(
                success=False,
                message=None,
                errors=[f"Table '{table_slug}' not found"],
            )
        except Exception as e:
            return MutationResult(
                success=False,
                message=None,
                errors=[str(e)],
            )
    
    @strawberry.mutation
    def create_view(
        self,
        info: Info,
        table_slug: str,
        input: CreateViewInput,
    ) -> MutationResult:
        """Create a custom view."""
        tenant = get_tenant_from_context(info)
        user = get_current_user(info)
        if not tenant or not user:
            return MutationResult(
                success=False,
                message=None,
                errors=["Authentication required"],
            )
        
        try:
            table = TableDefinition.objects.get(tenant=tenant, slug=table_slug)
            
            ViewService.create_view(
                table=table,
                user=user,
                name=input.name,
                columns=input.columns,
                sort=input.sort,
                filters=input.filters,
                is_default=input.is_default,
                is_shared=input.is_shared,
            )
            
            return MutationResult(
                success=True,
                message="View created successfully",
                errors=None,
            )
        except TableDefinition.DoesNotExist:
            return MutationResult(
                success=False,
                message=None,
                errors=[f"Table '{table_slug}' not found"],
            )
        except Exception as e:
            return MutationResult(
                success=False,
                message=None,
                errors=[str(e)],
            )
