"""
Flask middleware for payload-guard.
Provides request/response filtering for Flask applications.
"""

from __future__ import annotations
import json
from functools import wraps
from typing import Any, Callable, Optional

from flask import Flask, Request, Response, request, jsonify, g

from ..core.filter import build_shape, GuardConfig
from ..core.types import ShapeDescriptor, GuardMiddlewareOptions
from ..core.compiler import CompileOptions, compile_shape
from ..core.security import DEFAULT_SENSITIVE_FIELDS


class PayloadGuardMiddleware:
    """
    Flask middleware for payload filtering and sanitization.

    Example:
        from flask import Flask
        from payloadguard.flask import PayloadGuardMiddleware

        app = Flask(__name__)
        PayloadGuardMiddleware(app, request_shape={
            'name': 'string',
            'email': 'string',
        })
    """

    def __init__(
        self,
        app: Optional[Flask] = None,
        request_shape: Optional[ShapeDescriptor] = None,
        response_shape: Optional[ShapeDescriptor] = None,
        sensitive_fields: Optional[list[str]] = None,
        dev_mode: bool = False,
        strict: bool = False,
        max_array_length: Optional[int] = None,
        collect_errors: bool = False,
        ignore_routes: Optional[list[str]] = None,
        sanitize_body: bool = True,
        filter_response: bool = False,
        **kwargs,
    ):
        self.app = app
        self.request_shape = request_shape
        self.response_shape = response_shape
        self.sensitive_fields = sensitive_fields or []
        self.dev_mode = dev_mode
        self.strict = strict
        self.max_array_length = max_array_length
        self.collect_errors = collect_errors
        self.ignore_routes = ignore_routes or []
        self.sanitize_body = sanitize_body
        self.filter_response = filter_response
        self.extra_config = kwargs

        # Compile shapes
        self._request_filter = None
        self._response_filter = None

        if request_shape:
            self._request_filter = compile_shape(
                request_shape,
                CompileOptions(
                    sensitive=self.sensitive_fields + DEFAULT_SENSITIVE_FIELDS,
                    dev=dev_mode,
                    strict=strict,
                    max_array_length=max_array_length,
                    collect_errors=collect_errors,
                ),
            )

        if response_shape:
            self._response_filter = compile_shape(
                response_shape,
                CompileOptions(
                    sensitive=self.sensitive_fields + DEFAULT_SENSITIVE_FIELDS,
                    dev=dev_mode,
                    strict=strict,
                    max_array_length=max_array_length,
                    collect_errors=collect_errors,
                ),
            )

        if app is not None:
            self.init_app(app)

    def init_app(self, app: Flask) -> None:
        """Initialize middleware with Flask app."""
        app.before_request(self._before_request)
        app.after_request(self._after_request)

    def _should_ignore(self, path: str) -> bool:
        """Check if route should be ignored."""
        for prefix in self.ignore_routes:
            if path.startswith(prefix):
                return True
        return False

    def _before_request(self) -> Optional[Response]:
        """Process request before route handler."""
        if self._should_ignore(request.path):
            return None

        # Sanitize request body
        if self.sanitize_body and self._request_filter and request.method in ("POST", "PUT", "PATCH"):
            try:
                if request.is_json:
                    body = request.get_json()
                    sanitized_body = self._request_filter(body)
                    g.sanitized_body = sanitized_body
            except Exception as e:
                if self.dev_mode:
                    print(f"[payload-guard] Request sanitization error: {e}")

        return None

    def _after_request(self, response: Response) -> Response:
        """Process response after route handler."""
        if self._should_ignore(request.path):
            return response

        # Filter response
        if self.filter_response and self._response_filter and response.is_json:
            try:
                data = response.get_json()
                filtered_data = self._response_filter(data)

                # Create new response
                new_response = jsonify(filtered_data)
                new_response.status_code = response.status_code
                for key, value in response.headers.items():
                    if key.lower() not in ("content-length", "content-type"):
                        new_response.headers[key] = value
                return new_response
            except Exception as e:
                if self.dev_mode:
                    print(f"[payload-guard] Response filtering error: {e}")

        return response


def guard_middleware(
    app: Flask,
    request_shape: Optional[ShapeDescriptor] = None,
    response_shape: Optional[ShapeDescriptor] = None,
    options: Optional[GuardMiddlewareOptions] = None,
) -> None:
    """
    Add payload guard middleware to Flask app.

    Args:
        app: Flask application
        request_shape: Shape for request body sanitization
        response_shape: Shape for response filtering
        options: Middleware options
    """
    if options is None:
        options = GuardMiddlewareOptions()

    middleware = PayloadGuardMiddleware(
        app=app,
        request_shape=request_shape or options.request_shape,
        response_shape=response_shape or options.response_shape,
        sensitive_fields=options.sensitive_fields,
        dev_mode=options.dev_mode or False,
        strict=options.strict or False,
        max_array_length=options.max_array_length,
        collect_errors=options.collect_errors or False,
        sanitize_body=options.sanitize_body,
        filter_response=options.filter_response,
    )


def route_guard(
    shape: ShapeDescriptor,
    sensitive_fields: Optional[list[str]] = None,
    dev_mode: bool = False,
    strict: bool = False,
) -> Callable:
    """
    Decorator for route-level payload validation.

    Example:
        @app.route("/users", methods=["POST"])
        @route_guard(user_shape)
        def create_user():
            data = request.sanitized_body
            return jsonify(data)
    """

    def decorator(func: Callable) -> Callable:
        @wraps(func)
        def wrapper(*args, **kwargs):
            # Compile shape
            request_filter = compile_shape(
                shape,
                CompileOptions(
                    sensitive=(sensitive_fields or []) + DEFAULT_SENSITIVE_FIELDS,
                    dev=dev_mode,
                    strict=strict,
                ),
            )

            # Sanitize request body
            if request.is_json and request.method in ("POST", "PUT", "PATCH"):
                try:
                    body = request.get_json()
                    sanitized = request_filter(body)
                    g.sanitized_body = sanitized
                except Exception as e:
                    if dev_mode:
                        print(f"[payload-guard] Route guard error: {e}")

            return func(*args, **kwargs)

        return wrapper

    return decorator


def get_sanitized_body() -> Optional[dict]:
    """Get sanitized request body from Flask g object."""
    return getattr(g, "sanitized_body", None)
