"""
Feedback API for Match Quality Learning
========================================
Collects user feedback on match quality to improve future configurations.
"""

from fastapi import APIRouter, Depends, HTTPException
from typing import Dict, Any, Optional
from uuid import UUID
from pydantic import BaseModel
import logging

from ...auth import get_current_account
from ...db import get_session
from sqlalchemy.ext.asyncio import AsyncSession
from ...intelligence.decision_logger import DecisionLogger
from ...intelligence.bandits import ThresholdBandit, BlockingBandit
import redis.asyncio as async_redis

log = logging.getLogger(__name__)
router = APIRouter(prefix="/api/v2/feedback", tags=["feedback"])


# Pydantic models
class MatchFeedback(BaseModel):
    match_id: str
    job_id: str
    outcome: str  # 'accepted', 'reverted', 'corrected'
    corrected_target: Optional[str] = None
    confidence: Optional[float] = None  # User's confidence in their feedback
    notes: Optional[str] = None


class BulkFeedback(BaseModel):
    job_id: str
    accepted_matches: list[str] = []
    reverted_matches: list[str] = []
    corrected_matches: list[
        Dict[str, str]
    ] = []  # [{"match_id": "...", "correct_target": "..."}]


# Get Redis connection
async def get_redis():
    """Get Redis connection for feedback storage"""
    try:
        redis_conn = async_redis.Redis(
            host="localhost", port=6379, decode_responses=False
        )
        await redis_conn.ping()
        return redis_conn
    except Exception as e:
        log.error(f"Redis connection failed: {e}")
        return None


@router.post("/match")
async def record_match_feedback(
    feedback: MatchFeedback,
    db: AsyncSession = Depends(get_session),
    account_id: UUID = Depends(get_current_account),
) -> Dict[str, Any]:
    """
    Record feedback on a single match.
    Updates bandit statistics for continuous learning.
    """
    redis_conn = await get_redis()
    logger = DecisionLogger(redis_conn=redis_conn)

    # Log the feedback
    await logger.log_feedback(
        job_id=feedback.job_id,
        match_id=feedback.match_id,
        outcome=feedback.outcome,
        user_id=str(account_id),
        corrected_target=feedback.corrected_target,
    )

    # DecisionLogger will handle bandit updates internally

    return {
        "status": "recorded",
        "match_id": feedback.match_id,
        "message": f"Feedback recorded as '{feedback.outcome}'",
    }


@router.post("/bulk")
async def record_bulk_feedback(
    feedback: BulkFeedback,
    db: AsyncSession = Depends(get_session),
    account_id: UUID = Depends(get_current_account),
) -> Dict[str, Any]:
    """
    Record feedback on multiple matches at once.
    Useful for batch review workflows.
    """
    redis_conn = await get_redis()
    logger = DecisionLogger(redis_conn=redis_conn)

    processed = 0

    # Process accepted matches
    for match_id in feedback.accepted_matches:
        await logger.log_feedback(
            job_id=feedback.job_id,
            match_id=match_id,
            outcome="accepted",
            user_id=str(account_id),
        )
        processed += 1

    # Process reverted matches
    for match_id in feedback.reverted_matches:
        await logger.log_feedback(
            job_id=feedback.job_id,
            match_id=match_id,
            outcome="reverted",
            user_id=str(account_id),
        )
        processed += 1

    # Process corrected matches
    for correction in feedback.corrected_matches:
        await logger.log_feedback(
            job_id=feedback.job_id,
            match_id=correction["match_id"],
            outcome="corrected",
            user_id=str(account_id),
            corrected_target=correction.get("correct_target"),
        )
        processed += 1

    # Trigger batch learning update
    if processed > 0 and redis_conn:
        await _trigger_batch_learning(feedback.job_id, feedback, redis_conn)

    return {
        "status": "recorded",
        "job_id": feedback.job_id,
        "processed_count": processed,
        "breakdown": {
            "accepted": len(feedback.accepted_matches),
            "reverted": len(feedback.reverted_matches),
            "corrected": len(feedback.corrected_matches),
        },
    }


@router.get("/stats/{job_id}")
async def get_feedback_stats(
    job_id: str,
    db: AsyncSession = Depends(get_session),
    account_id: UUID = Depends(get_current_account),
) -> Dict[str, Any]:
    """
    Get feedback statistics for a job.
    Shows learning progress and configuration performance.
    """
    redis_conn = await get_redis()

    if not redis_conn:
        raise HTTPException(503, "Statistics service unavailable")

    import json

    # Get decision data
    decision_data = await redis_conn.get(f"decision:{job_id}")
    if not decision_data:
        raise HTTPException(404, f"No decision data found for job {job_id}")

    decision = json.loads(decision_data)
    segment = decision.get("segment", "unknown")

    # Get bandit performance
    threshold_bandit = ThresholdBandit(redis_conn)
    blocking_bandit = BlockingBandit(redis_conn)

    threshold_stats = await threshold_bandit.get_performance_summary(segment)
    blocking_stats = (
        await blocking_bandit.get_performance_summary(segment)
        if decision.get("blocking")
        else None
    )

    # Get feedback counts from logger
    logger = DecisionLogger(redis_conn=redis_conn)
    segment_perf = await logger.get_segment_performance(segment, days=30)

    return {
        "job_id": job_id,
        "segment": segment,
        "configuration_used": {
            "threshold_policy": decision.get("threshold"),
            "blocking_strategy": decision.get("blocking"),
        },
        "learning_stats": {"threshold": threshold_stats, "blocking": blocking_stats},
        "segment_performance": segment_perf,
        "message": "Learning system is adapting based on feedback",
    }


async def _trigger_batch_learning(job_id: str, feedback: BulkFeedback, redis_conn):
    """
    Process bulk feedback for learning.
    Calculates aggregate reward and updates bandits.
    """
    import json

    # Calculate aggregate reward
    total = (
        len(feedback.accepted_matches)
        + len(feedback.reverted_matches)
        + len(feedback.corrected_matches)
    )
    if total == 0:
        return

    accepted_weight = len(feedback.accepted_matches) / total
    reverted_weight = len(feedback.reverted_matches) / total
    corrected_weight = len(feedback.corrected_matches) / total

    # Weighted average reward
    aggregate_reward = (
        accepted_weight * 1.0 + corrected_weight * 0.3 + reverted_weight * 0.0
    )

    # Get decision configuration
    decision_data = await redis_conn.get(f"decision:{job_id}")
    if decision_data:
        decision = json.loads(decision_data)
        segment = decision.get("segment", "unknown")

        # Update bandits with aggregate reward
        if decision.get("threshold"):
            threshold_bandit = ThresholdBandit(redis_conn)
            await threshold_bandit.update(
                segment, decision["threshold"], aggregate_reward
            )

        if decision.get("blocking"):
            blocking_bandit = BlockingBandit(redis_conn)
            await blocking_bandit.update(
                segment, decision["blocking"], aggregate_reward
            )

        log.info(
            f"Batch learning update for job {job_id}: "
            f"aggregate_reward={aggregate_reward:.3f} from {total} feedback items"
        )
