"""Pydantic schemas for API validation and serialization."""

from datetime import datetime

from pydantic import BaseModel
from pydantic import ConfigDict
from pydantic import Field

from fenliu.custom_types import MediaAttachmentDict


class HashtagStreamBase(BaseModel):
    """Base schema for hashtag streams."""

    hashtag: str = Field(..., min_length=1, max_length=100, description="Hashtag to monitor (without #)")
    instance: str = Field(default="mastodon.social", max_length=200, description="Fediverse instance")
    active: bool = Field(default=True, description="Whether the stream is active")


class HashtagStreamCreate(HashtagStreamBase):
    """Schema for creating a new hashtag stream."""

    pass


class HashtagStreamUpdate(BaseModel):
    """Schema for updating a hashtag stream."""

    active: bool | None = None
    instance: str | None = Field(None, max_length=200)


class StreamSchedule(BaseModel):
    """Schema for stream scheduling configuration."""

    stream_id: int
    hashtag: str
    enable_scheduling: bool = Field(default=True, description="Whether scheduling is enabled")
    fetch_interval_minutes: int = Field(default=60, ge=5, le=1440, description="Minutes between fetches (5-1440)")
    next_scheduled_fetch: datetime | None = Field(None, description="Next scheduled fetch time")
    last_check: datetime | None = Field(None, description="Last time posts were fetched")

    model_config = ConfigDict(from_attributes=True)


class HashtagStreamResponse(HashtagStreamBase):
    """Schema for hashtag stream response."""

    id: int
    last_check: datetime | None = None
    created_at: datetime
    updated_at: datetime | None = None
    enable_scheduling: bool = Field(default=True, description="Whether scheduling is enabled")
    fetch_interval_minutes: int = Field(default=60, description="Minutes between fetches")
    next_scheduled_fetch: datetime | None = Field(None, description="Next scheduled fetch time")

    model_config = ConfigDict(from_attributes=True)


class PostBase(BaseModel):
    """Base schema for posts."""

    post_id: str = Field(..., max_length=100, description="Unique post identifier")
    content: str = Field(..., description="Post content")
    author_username: str | None = Field(None, max_length=100)
    author_display_name: str | None = Field(None, max_length=200)
    author_url: str | None = Field(None, max_length=500)
    instance: str = Field(..., max_length=200, description="Source instance")
    hashtags: list[str] | None = None
    media_attachments: list[MediaAttachmentDict] | None = None
    boosts: int = Field(default=0, ge=0)
    likes: int = Field(default=0, ge=0)
    replies: int = Field(default=0, ge=0)
    url: str | None = Field(None, max_length=500)
    created_at: datetime | None = None
    spam_score: int = Field(default=0, ge=0, le=100, description="Spam score (0-100)")


class PostCreate(PostBase):
    """Schema for creating a new post."""

    stream_id: int = Field(..., description="Associated hashtag stream ID")


class PostUpdate(BaseModel):
    """Schema for updating a post."""

    processed: bool | None = None
    spam_score: int | None = Field(None, ge=0, le=100)
    manual_spam_score: int | None = Field(None, ge=0, le=100, description="Manually adjusted spam score (0-100)")
    approved: bool | None = Field(None, description="True = approved, False = rejected, None = not reviewed")
    reviewer_notes: str | None = Field(None, max_length=1000, description="Notes from human reviewer")
    curated_exported: bool | None = Field(None, description="Whether exported to curated queue")


class PostResponse(PostBase):
    """Schema for post response."""

    id: int
    stream_id: int | None = None
    fetched_at: datetime
    processed: bool
    reviewed: bool = False
    reviewed_at: datetime | None = None
    reviewer_notes: str | None = None
    manual_spam_score: int | None = Field(None, ge=0, le=100, description="Manually adjusted spam score (0-100)")
    approved: bool | None = Field(None, description="True = approved, False = rejected, None = not reviewed")
    curated_exported: bool = False
    export_date: datetime | None = None
    training_data: bool = False
    queue_status: str | None = Field(None, description="Curated queue status: pending, reserved, delivered, error")

    model_config = ConfigDict(from_attributes=True)


class BlockedUserCreate(BaseModel):
    """Schema for adding a user to the blocklist."""

    account_identifier: str = Field(
        ...,
        min_length=1,
        max_length=500,
        description="Fediverse account identifier or pattern, e.g. @user@instance.social or *.bsky.app",
    )
    pattern_type: str = Field(default="exact", description="Pattern matching type: exact, suffix, prefix, contains")
    notes: str | None = Field(None, max_length=1000)


class BlockedUserResponse(BaseModel):
    """Schema for blocked user response."""

    id: int
    account_identifier: str
    pattern_type: str
    notes: str | None = None
    created_at: datetime

    model_config = ConfigDict(from_attributes=True)


class BlockedHashtagCreate(BaseModel):
    """Schema for adding a hashtag to the blocklist."""

    hashtag: str = Field(..., min_length=1, max_length=100, description="Hashtag to block (with or without leading #)")
    notes: str | None = Field(None, max_length=1000)


class BlockedHashtagResponse(BaseModel):
    """Schema for blocked hashtag response."""

    id: int
    hashtag: str
    notes: str | None = None
    created_at: datetime

    model_config = ConfigDict(from_attributes=True)


class ReblogSettingsUpdate(BaseModel):
    """Schema for updating global reblog export settings."""

    attachments_only: bool = Field(..., description="When true, only posts with media attachments are export-eligible")
    auto_reject_on_fetch: bool = Field(
        ..., description="When true, posts matching any reblog-control filter are automatically rejected on fetch"
    )
    auto_reject_bots: bool = Field(..., description="When true, posts from bot accounts are automatically rejected")


class ReblogSettingsResponse(BaseModel):
    """Schema for global reblog export settings response."""

    attachments_only: bool
    auto_reject_on_fetch: bool = False
    auto_reject_bots: bool = False


class StatsResponse(BaseModel):
    """Schema for application statistics."""

    total_streams: int
    active_streams: int
    total_posts: int
    processed_posts: int
    average_spam_score: float | None = None


class FetchResponse(BaseModel):
    """Schema for fetch operation response."""

    stream_id: int
    hashtag: str
    posts_fetched: int
    posts_saved: int
    success: bool
    error_message: str | None = None


class CuratedNextResponse(BaseModel):
    """Schema for the Curated /next queue response."""

    fenliu_post_id: int
    post_uri: str
    post_url: str | None = None
    author_account: str
    content_snippet: str
    hashtags: list[str]
    stream: str | None = None
    has_attachments: bool
    spam_score: int
    post_created_at: datetime | None = None
    approved_at: datetime | None = None


class CuratedErrorRequest(BaseModel):
    """Schema for the Curated /error request body."""

    reason: str = Field(..., min_length=1, max_length=1000, description="Reason for the permanent failure")
