"""
Cleaning Endpoints - Data cleaning operations.
"""

from fastapi import APIRouter, HTTPException, BackgroundTasks
from typing import Dict
import polars as pl
import time
import uuid

from app.api.models import CleanRequest, CleanResponse, IssueResponse
from app.engines.polars_detector import PolarsDetector, Issue
from app.engines.polars_fixer import PolarsFixer
from app.api.deps import get_current_user
from app.db.postgres import db
from app.core.redis import redis_client
from fastapi import Depends
import structlog

logger = structlog.get_logger(__name__)

router = APIRouter()


async def run_cleaning_task(result_id: str, request: CleanRequest, license_key: str):
    """Background task to clean data."""
    try:
        start_time = time.time()
        
        # Load files
        dfs = {}
        for file_path in request.files:
            try:
                df = pl.read_csv(file_path)
                dfs[file_path] = df
            except Exception as e:
                logger.error("file_load_error", file=file_path, error=str(e))
                continue
        
        if not dfs:
            await redis_client.set(f"job:{result_id}", {
                'status': 'error',
                'error': 'No files could be loaded'
            })
            return
        
        # Detect issues
        detector = PolarsDetector()
        all_issues = []
        
        for name, df in dfs.items():
            issues = detector.detect_all(df, dfs)
            all_issues.extend(issues)
        
        # Fix issues (if not flag_only)
        fixes_applied = 0
        if not request.flag_only:
            fixer = PolarsFixer()
            for name, df in dfs.items():
                df = fixer.apply_all_safe_fixes(df)
                dfs[name] = df
                fixes_applied += len(all_issues)
        
        # Merge if requested or single file
        merged_df = None
        if request.merge or len(dfs) == 1:
            if len(dfs) == 1:
                merged_df = list(dfs.values())[0]
            else:
                merged_df = pl.concat(list(dfs.values()), how='vertical')
        
        # Calculate quality score
        quality_score = max(0, 100 - (len(all_issues) * 2))
        
        processing_time = time.time() - start_time
        
        # Store result in Redis (without merged_df which is too large)
        await redis_client.set(f"job:{result_id}", {
            'status': 'complete',
            'files_processed': len(dfs),
            'issues_found': len(all_issues),
            'fixes_applied': fixes_applied,
            'quality_score': quality_score,
            'processing_time_seconds': processing_time,
            'issues': [{'issue_type': i.issue_type, 'severity': i.severity, 'description': i.description} for i in all_issues]
        }, ttl=3600)  # 1 hour TTL
        
        logger.info("cleaning_complete",
            result_id=result_id,
            files=len(dfs),
            issues=len(all_issues),
            time=processing_time)

        # Save to DB
        try:
            await db.execute(
                """
                INSERT INTO jobs (id, license_key, filename, status, quality_score, issues_found, fixes_applied, completed_at)
                VALUES ($1, $2, $3, $4, $5, $6, $7, CURRENT_TIMESTAMP)
                """,
                result_id,
                license_key,
                str(request.files[0]) if request.files else "unknown",
                'completed',
                quality_score,
                len(all_issues),
                fixes_applied
            )
        except Exception as e:
            logger.error("db_save_error", error=str(e))
            
        # Trigger Webhook
        try:
            from app.utils.webhooks import WebhookDispatcher
            await WebhookDispatcher.dispatch(
                license_key,
                'job.completed',
                {
                    'job_id': result_id,
                    'status': 'completed',
                    'quality_score': quality_score,
                    'issues_found': len(all_issues)
                }
            )
        except Exception as e:
            logger.error("webhook_dispatch_error", error=str(e))
    
    except Exception as e:
        logger.error("cleaning_error", result_id=result_id, error=str(e))
        await redis_client.set(f"job:{result_id}", {
            'status': 'error',
            'error': str(e)
        })
        # Save error to DB
        try:
            await db.execute(
                """
                INSERT INTO jobs (id, license_key, filename, status, error, created_at)
                VALUES ($1, $2, $3, $4, $5, CURRENT_TIMESTAMP)
                """,
                result_id,
                license_key,
                str(request.files[0]) if request.files else "unknown",
                'error',
                str(e)
            )
        except Exception as db_e:
            logger.error("db_save_error_on_fail", error=str(db_e))


@router.post("/clean", response_model=CleanResponse)
async def clean_data(
    request: CleanRequest, 
    background_tasks: BackgroundTasks,
    current_user: dict = Depends(get_current_user)
):
    """
    Clean data files.
    
    Processes files in background and returns result_id for polling.
    """
    result_id = str(uuid.uuid4())
    
    logger.info("clean_request",
        result_id=result_id,
        files=len(request.files),
        conservative=request.conservative)
    
    # Start background task
    await redis_client.set(f"job:{result_id}", {'status': 'processing'})
    background_tasks.add_task(run_cleaning_task, result_id, request, current_user['license_key'])
    
    return CleanResponse(
        result_id=result_id,
        files_processed=0,
        issues_found=0,
        fixes_applied=0,
        quality_score=0.0,
        processing_time_seconds=0.0,
        issues=[]
    )


@router.get("/clean/{result_id}")
async def get_clean_result(result_id: str):
    """Get cleaning result by ID."""
    result = await redis_client.get(f"job:{result_id}")
    if not result:
        raise HTTPException(status_code=404, detail="Result not found")
    
    if result['status'] == 'processing':
        return {'status': 'processing'}
    
    if result['status'] == 'error':
        raise HTTPException(status_code=500, detail=result.get('error', 'Unknown error'))
    
    # Convert Polars issues to response format
    issues = [
        IssueResponse(
            issue_type=issue.issue_type,
            severity=issue.severity,
            description=issue.description,
            affected_items=issue.affected_items,
            fix_available=issue.fix_available
        )
        for issue in result.get('issues', [])
    ]
    
    return CleanResponse(
        result_id=result_id,
        files_processed=result['files_processed'],
        issues_found=result['issues_found'],
        fixes_applied=result['fixes_applied'],
        quality_score=result['quality_score'],
        processing_time_seconds=result['processing_time_seconds'],
        issues=issues
    )


@router.get("/clean/{result_id}/download")
async def download_clean_result(result_id: str):
    """Download cleaned data as CSV."""
    from fastapi.responses import StreamingResponse
    import io
    
    if result_id not in results_cache:
        raise HTTPException(status_code=404, detail="Result not found")
    
    result = results_cache[result_id]
    
    if result['status'] != 'complete':
        raise HTTPException(status_code=400, detail="Processing not complete")
        
    df = result.get('merged_df')
    if df is None:
        raise HTTPException(status_code=400, detail="No merged data available")
        
    # Convert to CSV
    buffer = io.BytesIO()
    df.write_csv(buffer)
    buffer.seek(0)
    
    return StreamingResponse(
        buffer,
        media_type="text/csv",
        headers={"Content-Disposition": f"attachment; filename=cleaned_data_{result_id[:8]}.csv"}
    )


@router.get("/clean/{result_id}/report")
async def get_clean_report(result_id: str):
    """Download cleaning report as a premium HTML dashboard."""
    from fastapi.responses import HTMLResponse
    import json
    
    if result_id not in results_cache:
        raise HTTPException(status_code=404, detail="Result not found")
    
    result = results_cache[result_id]
    
    if result['status'] != 'complete':
        raise HTTPException(status_code=400, detail="Processing not complete")
        
    # Prepare data for charts
    issues_by_type = {}
    for issue in result['issues']:
        issues_by_type[issue.issue_type] = issues_by_type.get(issue.issue_type, 0) + 1
        
    df = result.get('merged_df')
    column_stats = []
    if df is not None:
        for col in df.columns:
            null_count = df[col].null_count()
            column_stats.append({
                'name': col,
                'type': str(df[col].dtype),
                'nulls': null_count,
                'unique': df[col].n_unique()
            })

    # Premium HTML Template
    html_content = f"""
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Data Quality Report - {result_id[:8]}</title>
        <script src="https://cdn.tailwindcss.com"></script>
        <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
        <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
        <style>
            body {{ font-family: 'Inter', sans-serif; background-color: #f8fafc; }}
            .glass {{ background: white; border: 1px solid #e2e8f0; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); }}
        </style>
    </head>
    <body class="text-slate-800">
        <!-- Header -->
        <div class="bg-white border-b border-slate-200 sticky top-0 z-50">
            <div class="max-w-7xl mx-auto px-6 py-4 flex justify-between items-center">
                <div class="flex items-center gap-3">
                    <div class="w-10 h-10 bg-indigo-600 rounded-lg flex items-center justify-center text-white font-bold text-xl">DS</div>
                    <div>
                        <h1 class="font-bold text-xl text-slate-900">Data Quality Report</h1>
                        <p class="text-xs text-slate-500">ID: {result_id}</p>
                    </div>
                </div>
                <div class="flex gap-4">
                    <div class="text-right">
                        <p class="text-xs text-slate-500 uppercase tracking-wider font-semibold">Quality Score</p>
                        <p class="text-2xl font-bold {'text-green-600' if result['quality_score'] >= 90 else 'text-yellow-600'}">{result['quality_score']}%</p>
                    </div>
                </div>
            </div>
        </div>

        <div class="max-w-7xl mx-auto px-6 py-8 space-y-8">
            
            <!-- KPI Grid -->
            <div class="grid grid-cols-1 md:grid-cols-4 gap-6">
                <div class="glass rounded-xl p-6">
                    <p class="text-sm text-slate-500 font-medium">Files Processed</p>
                    <p class="text-3xl font-bold text-slate-900 mt-2">{result['files_processed']}</p>
                </div>
                <div class="glass rounded-xl p-6">
                    <p class="text-sm text-slate-500 font-medium">Issues Found</p>
                    <p class="text-3xl font-bold text-amber-600 mt-2">{result['issues_found']}</p>
                </div>
                <div class="glass rounded-xl p-6">
                    <p class="text-sm text-slate-500 font-medium">Fixes Applied</p>
                    <p class="text-3xl font-bold text-green-600 mt-2">{result['fixes_applied']}</p>
                </div>
                <div class="glass rounded-xl p-6">
                    <p class="text-sm text-slate-500 font-medium">Processing Time</p>
                    <p class="text-3xl font-bold text-indigo-600 mt-2">{result['processing_time_seconds']:.2f}s</p>
                </div>
            </div>

            <!-- Charts Section -->
            <div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
                <div class="glass rounded-xl p-6">
                    <h3 class="font-bold text-lg mb-6">Issue Distribution</h3>
                    <canvas id="issuesChart"></canvas>
                </div>
                <div class="glass rounded-xl p-6">
                    <h3 class="font-bold text-lg mb-6">Column Health (Missing Values)</h3>
                    <canvas id="healthChart"></canvas>
                </div>
            </div>

            <!-- Detailed Issues -->
            <div class="glass rounded-xl overflow-hidden">
                <div class="px-6 py-4 border-b border-slate-200 bg-slate-50">
                    <h3 class="font-bold text-lg text-slate-900">Detected Issues</h3>
                </div>
                <div class="divide-y divide-slate-200">
                    {''.join([f'''
                    <div class="p-6 hover:bg-slate-50 transition-colors">
                        <div class="flex items-start justify-between">
                            <div class="flex gap-4">
                                <span class="px-3 py-1 rounded-full text-xs font-medium bg-amber-100 text-amber-800 h-fit whitespace-nowrap">
                                    {i.issue_type}
                                </span>
                                <div>
                                    <p class="font-medium text-slate-900">{i.description}</p>
                                    <p class="text-sm text-slate-500 mt-1">Affected: {', '.join(i.affected_items[:5])}{'...' if len(i.affected_items) > 5 else ''}</p>
                                </div>
                            </div>
                            <span class="text-xs font-medium {'text-green-600 bg-green-50' if i.fix_available else 'text-slate-500 bg-slate-100'} px-2 py-1 rounded">
                                {'Auto-Fixed' if i.fix_available else 'Manual Review'}
                            </span>
                        </div>
                    </div>
                    ''' for i in result['issues']])}
                    { '<div class="p-8 text-center text-slate-500">No issues found! 🎉</div>' if not result['issues'] else '' }
                </div>
            </div>

            <!-- Schema Info -->
            <div class="glass rounded-xl overflow-hidden">
                <div class="px-6 py-4 border-b border-slate-200 bg-slate-50">
                    <h3 class="font-bold text-lg text-slate-900">Dataset Schema</h3>
                </div>
                <div class="overflow-x-auto">
                    <table class="w-full text-left text-sm">
                        <thead class="bg-slate-50 text-slate-500 font-medium border-b border-slate-200">
                            <tr>
                                <th class="px-6 py-3">Column</th>
                                <th class="px-6 py-3">Type</th>
                                <th class="px-6 py-3">Unique Values</th>
                                <th class="px-6 py-3">Missing Values</th>
                            </tr>
                        </thead>
                        <tbody class="divide-y divide-slate-200">
                            {''.join([f'''
                            <tr>
                                <td class="px-6 py-3 font-medium text-slate-900">{c['name']}</td>
                                <td class="px-6 py-3 text-slate-500"><span class="font-mono bg-slate-100 px-2 py-0.5 rounded text-xs">{c['type']}</span></td>
                                <td class="px-6 py-3 text-slate-500">{c['unique']}</td>
                                <td class="px-6 py-3">
                                    <div class="flex items-center gap-2">
                                        <div class="w-24 h-1.5 bg-slate-100 rounded-full overflow-hidden">
                                            <div class="h-full bg-red-500" style="width: {(c['nulls'] / (df.height if df else 1) * 100)}%"></div>
                                        </div>
                                        <span class="text-xs text-slate-500">{c['nulls']}</span>
                                    </div>
                                </td>
                            </tr>
                            ''' for c in column_stats])}
                        </tbody>
                    </table>
                </div>
            </div>
        </div>

        <script>
            // Issues Chart
            const ctxIssues = document.getElementById('issuesChart').getContext('2d');
            new Chart(ctxIssues, {{
                type: 'doughnut',
                data: {{
                    labels: {json.dumps(list(issues_by_type.keys()))},
                    datasets: [{{
                        data: {json.dumps(list(issues_by_type.values()))},
                        backgroundColor: ['#4f46e5', '#06b6d4', '#8b5cf6', '#ec4899', '#f59e0b'],
                        borderWidth: 0
                    }}]
                }},
                options: {{
                    responsive: true,
                    plugins: {{
                        legend: {{ position: 'right' }}
                    }},
                    cutout: '70%'
                }}
            }});

            // Health Chart
            const ctxHealth = document.getElementById('healthChart').getContext('2d');
            new Chart(ctxHealth, {{
                type: 'bar',
                data: {{
                    labels: {json.dumps([c['name'] for c in column_stats])},
                    datasets: [{{
                        label: 'Missing Values',
                        data: {json.dumps([c['nulls'] for c in column_stats])},
                        backgroundColor: '#ef4444',
                        borderRadius: 4
                    }}]
                }},
                options: {{
                    responsive: true,
                    scales: {{
                        y: {{ beginAtZero: true }}
                    }},
                    plugins: {{
                        legend: {{ display: false }}
                    }}
                }}
            }});
        </script>
    </body>
    </html>
    """
    
    return HTMLResponse(content=html_content)


@router.get("/clean/{result_id}/schema")
async def get_clean_schema(result_id: str):
    """Download schema as JSON."""
    from fastapi.responses import JSONResponse
    import json
    
    if result_id not in results_cache:
        raise HTTPException(status_code=404, detail="Result not found")
    
    result = results_cache[result_id]
    
    if result['status'] != 'complete':
        raise HTTPException(status_code=400, detail="Processing not complete")
        
    df = result.get('merged_df')
    if df is None:
        raise HTTPException(status_code=400, detail="No merged data available")
        
    # Infer schema from Polars DataFrame
    schema = {
        "fields": [
            {"name": name, "type": str(dtype)}
            for name, dtype in df.schema.items()
        ],
        "metadata": {
            "rows": df.height,
            "columns": df.width
        }
    }
    
    return JSONResponse(
        content=schema,
        headers={"Content-Disposition": f"attachment; filename=schema_{result_id[:8]}.json"}
    )
