from typing import List, Optional
from pydantic import model_validator
from pydantic_settings import BaseSettings, SettingsConfigDict


class Settings(BaseSettings):
    model_config = SettingsConfigDict(
        env_file=".env",
        env_file_encoding="utf-8",
        case_sensitive=False,
        extra="ignore",
    )

    # Application
    APP_NAME: str = "INDELIS API"
    APP_VERSION: str = "1.0.0"
    ENVIRONMENT: str = "development"
    DEBUG: bool = False
    LOG_LEVEL: str = "INFO"

    # Database
    DATABASE_URL: str = "postgresql+psycopg://postgres:password@localhost:5432/indelis"
    POSTGRES_DB: str = "indelis"
    POSTGRES_USER: str = "postgres"
    POSTGRES_PASSWORD: str = "password"
    POSTGRES_HOST: str = "localhost"
    POSTGRES_PORT: int = 5432
    DB_POOL_SIZE: int = 10
    DB_MAX_OVERFLOW: int = 20

    # JWT
    JWT_SECRET: str = "change-me-in-production"
    JWT_REFRESH_SECRET: str = "change-me-refresh-in-production"
    JWT_ALGORITHM: str = "HS256"
    JWT_ACCESS_TOKEN_EXPIRE_MINUTES: int = 15
    JWT_REFRESH_TOKEN_EXPIRE_DAYS: int = 7

    # Redis
    REDIS_URL: str = "redis://localhost:6379/0"
    REDIS_TENANT_CACHE_TTL: int = 3600  # 1 hour

    # CORS
    ALLOWED_ORIGINS: List[str] = [
        "http://localhost:3000",
        "http://localhost:3001",
        "http://localhost:5173",
        "http://localhost:5174",
        "http://green-hills.localhost:3000",
        "http://green-hills.localhost:3001",
        "https://indelis-ui-uat.dreamztesting.com",
        "https://indelis-admin-uat.dreamztesting.com",
        "https://indelis-ui-dev.dreamztesting.com",
        "https://indelis-admin-dev.dreamztesting.com",
        "https://green-hills-ui-uat.dreamztesting.com",
        "https://green-hills-admin-uat.dreamztesting.com",
        "https://green-hills-ui-dev.dreamztesting.com",
        "https://green-hills-admin-dev.dreamztesting.com",
    ]
    ALLOWED_METHODS: List[str] = ["*"]
    ALLOWED_HEADERS: List[str] = ["*"]

    # AWS S3
    AWS_ACCESS_KEY_ID: str = ""
    AWS_SECRET_ACCESS_KEY: str = ""
    AWS_REGION: str = "us-east-1"
    S3_BUCKET: str = "indelis-dev-uat"
    S3_DOCUMENTS_BUCKET: str = "indelis-dev-uat"
    S3_DOCUMENTS_REGION: str = "us-east-1"
    CLOUDFRONT_URL: str = "https://d16xufzn5inupa.cloudfront.net"
    CLOUDFRONT_DOCUMENTS_URL: str = "https://d16xufzn5inupa.cloudfront.net"

    # AI
    ANTHROPIC_API_KEY: str = ""
    OPENAI_API_KEY: str = ""
    # Model/params for the public AI-search endpoint (INDL-48). Kept env-driven
    # (rather than hardcoded like the existing biography endpoint) so the model
    # can be rotated without a deploy — see A06 in the INDL-48 security review.
    ANTHROPIC_MODEL: str = "claude-haiku-4-5-20251001"
    ANTHROPIC_MAX_TOKENS: int = 1024

    # Google Maps (INDL-49 — server-side Geocoding API proxy; key never sent to client)
    GOOGLE_MAPS_API_KEY: str = ""

    # Stripe
    STRIPE_SECRET_KEY: str = ""
    STRIPE_PUBLISHABLE_KEY: str = ""
    STRIPE_WEBHOOK_SECRET: str = ""
    # Price IDs from your Stripe dashboard (Products → Prices)
    STRIPE_PRICE_STARTER: str = ""
    STRIPE_PRICE_PROFESSIONAL: str = ""
    STRIPE_PRICE_ENTERPRISE: str = ""
    STRIPE_TRIAL_DAYS: int = 14

    # Email (AWS SES)
    SES_FROM_EMAIL: str = "noreply@indelis.com"
    SES_FROM_NAME: str = "INDELIS"

    # Domain
    APP_DOMAIN: str = "indelis.com"
    SYSTEM_SUBDOMAINS: List[str] = ["www", "admin", "api", "mail", "smtp"]
    # Base domain used when building per-tenant payment link URLs.
    # Leave empty to use APP_DOMAIN.
    # Set in .env for local dev:  PORTAL_BASE_DOMAIN=localhost:3001
    # Set in .env for UAT:        PORTAL_BASE_DOMAIN=uat.indelis.com
    PORTAL_BASE_DOMAIN: str = ""

    # Full URL template for a tenant's PUBLIC memorial site (INDL-40 dashboard
    # banner). Use the literal token {subdomain} — it is replaced with the
    # tenant's subdomain. Leave empty to default to production:
    #   https://{subdomain}.{APP_DOMAIN}
    # Set per environment in .env:
    #   Local:  PUBLIC_SITE_URL_TEMPLATE=http://{subdomain}.localhost:3001
    #   Dev:    PUBLIC_SITE_URL_TEMPLATE=https://{subdomain}-ui-dev.dreamztesting.com
    #   UAT:    PUBLIC_SITE_URL_TEMPLATE=https://{subdomain}-ui-uat.dreamztesting.com
    PUBLIC_SITE_URL_TEMPLATE: str = ""

    # App Environment & Workspace URL
    APP_ENV: str = "development"          # development | staging | production
    FRONTEND_PORT: int = 3001
    PUBLIC_BASE_DOMAIN: str = "indelis.com"
    # Full URL of the marketing/signup frontend — used in outbound email links.
    # Leave empty to auto-derive:
    #   ENVIRONMENT=development  → http://localhost:{FRONTEND_PORT}
    #   ENVIRONMENT=production   → https://{APP_DOMAIN}
    #   anything else            → https://{APP_DOMAIN}
    # Override explicitly in .env for dev/UAT deployments:
    #   FRONTEND_URL=https://indelis-ui-dev.dreamztesting.com
    FRONTEND_URL: Optional[str] = None
    # Admin portal URL — used for invitation links (team members log in via the admin portal, not the public site)
    ADMIN_PORTAL_URL: str = "http://localhost:3000"

    # SMTP Email
    SMTP_HOST: str = ""
    SMTP_PORT: int = 587
    SMTP_USER: str = ""
    SMTP_PASSWORD: str = ""
    EMAIL_FROM: str = "noreply@indelis.com"

    # reCAPTCHA
    RECAPTCHA_SECRET_KEY: str = ""  # leave empty to skip server-side verification in dev

    # Rate Limiting
    RATE_LIMIT_DEFAULT: str = "100/minute"
    RATE_LIMIT_AI: str = "10/minute"
    RATE_LIMIT_PUBLIC_SEARCH: str = "5/minute"

    @model_validator(mode='after')
    def _resolve_frontend_url(self) -> 'Settings':
        """Resolve FRONTEND_URL: use explicit value if set, else fall back to localhost."""
        if not self.FRONTEND_URL:
            self.FRONTEND_URL = f'http://localhost:{self.FRONTEND_PORT}'
        self.FRONTEND_URL = self.FRONTEND_URL.rstrip('/')
        return self

    @model_validator(mode='after')
    def _validate_jwt_secrets(self) -> 'Settings':
        """Fail fast in production if JWT secrets are default or too weak (A07).

        Only enforced when ENVIRONMENT == 'production' so local/dev keep working
        with the built-in defaults.
        """
        if self.ENVIRONMENT != "production":
            return self

        _defaults = {"change-me-in-production", "change-me-refresh-in-production"}
        for field_name in ("JWT_SECRET", "JWT_REFRESH_SECRET"):
            value = getattr(self, field_name)
            if value in _defaults:
                raise ValueError(
                    f"{field_name} must be set to a strong secret in production "
                    f"(the default placeholder value is not allowed)."
                )
            if len(value) < 32:
                raise ValueError(
                    f"{field_name} must be at least 32 characters long in production."
                )
        return self

    @property
    def is_production(self) -> bool:
        return self.ENVIRONMENT == "production"

    @property
    def is_development(self) -> bool:
        return self.ENVIRONMENT == "development"


settings = Settings()
