from datetime import datetime
from typing import Optional, List
from pydantic import BaseModel, Field, field_validator
from src.core.utils.enums import SUBSCRIBABLE_WEBHOOK_EVENTS


class CreateWebhookRequest(BaseModel):
    display_name: str = Field(..., min_length=1, max_length=100)
    url: str = Field(...)
    events: List[str] = Field(..., min_length=1)

    @field_validator("url")
    @classmethod
    def validate_url(cls, v: str) -> str:
        import re
        # Allow https:// for production, also allow http://localhost, http://127., http://192.168. etc for dev testing
        if not (v.startswith("https://") or
                re.match(r"^http://(localhost|127\.\d+\.\d+\.\d+|192\.168\.\d+\.\d+|10\.\d+\.\d+\.\d+|172\.(1[6-9]|2\d|3[01])\.\d+\.\d+)", v)):
            raise ValueError("URL must be https:// or a local/RFC-1918 address for testing")
        return v

    @field_validator("events")
    @classmethod
    def validate_events(cls, v: List[str]) -> List[str]:
        invalid = [e for e in v if e not in SUBSCRIBABLE_WEBHOOK_EVENTS]
        if invalid:
            raise ValueError(f"Invalid event types: {invalid}. Must be one of: {SUBSCRIBABLE_WEBHOOK_EVENTS}")
        return v


class WebhookCreatedResponse(BaseModel):
    id: int
    display_name: str
    url: str
    events: List[str]
    signing_secret: str
    is_active: bool
    created_at: datetime

    class Config:
        from_attributes = True


class WebhookResponse(BaseModel):
    id: int
    display_name: str
    url: str
    events: List[str]
    is_active: bool
    last_triggered_at: Optional[datetime] = None
    failure_count: int
    created_at: datetime

    class Config:
        from_attributes = True


class UpdateWebhookRequest(BaseModel):
    display_name: Optional[str] = Field(None, max_length=100)
    url: Optional[str] = None
    events: Optional[List[str]] = None
    is_active: Optional[bool] = None

    @field_validator("url")
    @classmethod
    def validate_url(cls, v: Optional[str]) -> Optional[str]:
        if v is None:
            return v
        import re
        if not (v.startswith("https://") or
                re.match(r"^http://(localhost|127\.\d+\.\d+\.\d+|192\.168\.\d+\.\d+|10\.\d+\.\d+\.\d+|172\.(1[6-9]|2\d|3[01])\.\d+\.\d+)", v)):
            raise ValueError("URL must be https:// or a local/RFC-1918 address for testing")
        return v

    @field_validator("events")
    @classmethod
    def validate_events(cls, v: Optional[List[str]]) -> Optional[List[str]]:
        if v is None:
            return v
        invalid = [e for e in v if e not in SUBSCRIBABLE_WEBHOOK_EVENTS]
        if invalid:
            raise ValueError(f"Invalid event types: {invalid}.")
        return v


class WebhookDeliveryResponse(BaseModel):
    id: int
    event_type: str
    event_id: str
    payload: Optional[dict] = None
    response_status: Optional[int] = None
    response_body: Optional[str] = None
    attempt_count: int
    delivered_at: Optional[datetime] = None
    failed_at: Optional[datetime] = None
    created_at: datetime

    class Config:
        from_attributes = True


class ApiRequestLogResponse(BaseModel):
    id: int
    key_id: str
    method: str
    path: str
    query_params: Optional[dict] = None
    status_code: int
    duration_ms: int
    ip_address: str
    request_id: str
    error_message: Optional[str] = None
    created_at: datetime

    class Config:
        from_attributes = True


class ApiRequestLogDetailResponse(ApiRequestLogResponse):
    """Extended log detail with request/response bodies and related entity info resolved from the path."""
    request_body: Optional[dict] = None
    response_body: Optional[dict] = None
    related_entity_type: Optional[str] = None   # "transaction" | "payment_request" | "customer" | etc.
    related_entity_id: Optional[int] = None
    customer_name: Optional[str] = None
    customer_email: Optional[str] = None
    transaction_amount: Optional[float] = None
    transaction_status: Optional[str] = None
    transaction_literal: Optional[str] = None
    payment_request_literal: Optional[str] = None
    payment_request_amount: Optional[float] = None
    payment_request_status: Optional[str] = None
