"""Web dashboard integration for cost tracking.

Provides FastAPI endpoints for:
- Cost dashboard HTML/JS
- API endpoints for cost data
- Real-time budget alerts via WebSocket
"""

from __future__ import annotations

from datetime import datetime
from pathlib import Path
from typing import Any

from fastapi import APIRouter, HTTPException, Query
from fastapi.responses import HTMLResponse
from pydantic import BaseModel

from oclawma.costs import (
    BudgetManager,
    CostStore,
    CostTracker,
    ReportPeriod,
)


def get_costs_db_path() -> Path:
    """Get the default costs database path."""
    return Path.home() / ".oclawma" / "costs" / "costs.db"


def get_cost_store() -> CostStore:
    """Get cost store instance."""
    return CostStore(get_costs_db_path())


# API Models
class BudgetCreateRequest(BaseModel):
    """Request to create a budget."""

    name: str
    monthly_limit: float
    project_id: str | None = None
    tenant_id: str | None = None
    alert_thresholds: list[int] | None = None


class BudgetUpdateRequest(BaseModel):
    """Request to update a budget."""

    name: str | None = None
    monthly_limit: float | None = None
    alert_thresholds: list[int] | None = None


class CostReportResponse(BaseModel):
    """Cost report response."""

    period: str
    start_date: str
    end_date: str
    total_cost: float
    total_jobs: int
    costs_by_project: dict[str, float]
    costs_by_tenant: dict[str, float]
    costs_by_provider: dict[str, float]
    top_jobs: list[dict[str, Any]]
    daily_breakdown: dict[str, float]


def create_costs_router() -> APIRouter:
    """Create the costs API router.

    Returns:
        Configured APIRouter instance
    """
    router = APIRouter(prefix="/costs", tags=["costs"])

    # =============================================================================
    # Dashboard HTML
    # =============================================================================

    @router.get("/dashboard", response_class=HTMLResponse)
    async def costs_dashboard() -> str:
        """Serve the cost tracking dashboard."""
        return _get_dashboard_html()

    # =============================================================================
    # Report API
    # =============================================================================

    @router.get("/api/report")
    async def get_report(
        period: str = Query("daily", description="Report period"),
        project_id: str | None = Query(None, description="Filter by project"),
        tenant_id: str | None = Query(None, description="Filter by tenant"),
    ) -> dict[str, Any]:
        """Get cost attribution report."""
        store = get_cost_store()
        tracker = CostTracker(store)

        try:
            report_period = ReportPeriod(period.lower())
            report = tracker.generate_report(
                period=report_period,
                project_id=project_id,
                tenant_id=tenant_id,
            )
            return report.to_dict()
        finally:
            tracker.close()

    @router.get("/api/stats")
    async def get_stats() -> dict[str, Any]:
        """Get summary statistics."""
        store = get_cost_store()
        tracker = CostTracker(store)
        manager = BudgetManager(store)

        try:
            # Get daily report for recent stats
            report = tracker.generate_report(ReportPeriod.DAILY)
            weekly_report = tracker.generate_report(ReportPeriod.WEEKLY)
            monthly_report = tracker.generate_report(ReportPeriod.MONTHLY)

            # Get budget info
            budgets = manager.list_budgets()
            budget_status = []
            for budget in budgets:
                usage = manager.get_budget_usage(budget.id)
                if usage:
                    budget_status.append(
                        {
                            "id": budget.id,
                            "name": budget.name,
                            "limit": usage["monthly_limit"],
                            "current": usage["current_usage"],
                            "remaining": usage["remaining"],
                            "percent": usage["usage_percent"],
                        }
                    )

            return {
                "daily": {
                    "total_cost": report.total_cost,
                    "total_jobs": report.total_jobs,
                },
                "weekly": {
                    "total_cost": weekly_report.total_cost,
                    "total_jobs": weekly_report.total_jobs,
                },
                "monthly": {
                    "total_cost": monthly_report.total_cost,
                    "total_jobs": monthly_report.total_jobs,
                },
                "budgets": budget_status,
                "timestamp": datetime.utcnow().isoformat(),
            }
        finally:
            tracker.close()

    # =============================================================================
    # Jobs API
    # =============================================================================

    @router.get("/api/jobs")
    async def list_jobs(
        project_id: str | None = Query(None),
        tenant_id: str | None = Query(None),
        limit: int = Query(50, ge=1, le=500),
        offset: int = Query(0, ge=0),
    ) -> list[dict[str, Any]]:
        """List job costs with pagination."""
        store = get_cost_store()

        try:
            jobs = store.get_job_costs(
                project_id=project_id,
                tenant_id=tenant_id,
                limit=limit,
            )
            return [job.to_dict() for job in jobs]
        finally:
            store.close()

    @router.get("/api/jobs/{job_id}")
    async def get_job(job_id: str) -> dict[str, Any]:
        """Get detailed cost information for a job."""
        store = get_cost_store()

        try:
            job = store.get_job_cost(job_id)
            if not job:
                raise HTTPException(status_code=404, detail="Job not found")
            return job.to_dict()
        finally:
            store.close()

    # =============================================================================
    # Budget API
    # =============================================================================

    @router.get("/api/budgets")
    async def list_budgets(
        project_id: str | None = Query(None),
        tenant_id: str | None = Query(None),
    ) -> list[dict[str, Any]]:
        """List all budgets."""
        store = get_cost_store()
        manager = BudgetManager(store)

        try:
            budgets = manager.list_budgets(project_id=project_id, tenant_id=tenant_id)
            result = []
            for budget in budgets:
                data = budget.to_dict()
                usage = manager.get_budget_usage(budget.id)
                if usage:
                    data["usage"] = usage
                result.append(data)
            return result
        finally:
            store.close()

    @router.post("/api/budgets")
    async def create_budget(request: BudgetCreateRequest) -> dict[str, Any]:
        """Create a new budget."""
        store = get_cost_store()
        manager = BudgetManager(store)

        try:
            budget = manager.create_budget(
                name=request.name,
                project_id=request.project_id,
                tenant_id=request.tenant_id,
                monthly_limit=request.monthly_limit,
                alert_thresholds=request.alert_thresholds,
            )
            return budget.to_dict()
        finally:
            store.close()

    @router.get("/api/budgets/{budget_id}")
    async def get_budget(budget_id: str) -> dict[str, Any]:
        """Get a specific budget."""
        store = get_cost_store()
        manager = BudgetManager(store)

        try:
            budget = manager.get_budget(budget_id)
            if not budget:
                raise HTTPException(status_code=404, detail="Budget not found")

            data = budget.to_dict()
            usage = manager.get_budget_usage(budget_id)
            if usage:
                data["usage"] = usage

            return data
        finally:
            store.close()

    @router.put("/api/budgets/{budget_id}")
    async def update_budget(budget_id: str, request: BudgetUpdateRequest) -> dict[str, Any]:
        """Update a budget."""
        store = get_cost_store()
        manager = BudgetManager(store)

        try:
            budget = manager.update_budget(
                budget_id=budget_id,
                name=request.name,
                monthly_limit=request.monthly_limit,
                alert_thresholds=request.alert_thresholds,
            )
            if not budget:
                raise HTTPException(status_code=404, detail="Budget not found")
            return budget.to_dict()
        finally:
            store.close()

    @router.delete("/api/budgets/{budget_id}")
    async def delete_budget(budget_id: str) -> dict[str, bool]:
        """Delete a budget."""
        store = get_cost_store()
        manager = BudgetManager(store)

        try:
            success = manager.delete_budget(budget_id)
            if not success:
                raise HTTPException(status_code=404, detail="Budget not found")
            return {"deleted": True}
        finally:
            store.close()

    @router.post("/api/budgets/{budget_id}/check")
    async def check_budget(budget_id: str) -> list[dict[str, Any]]:
        """Check budget status and return alerts."""
        store = get_cost_store()
        manager = BudgetManager(store)

        try:
            alerts = manager.check_budget(budget_id)
            return [
                {
                    "level": alert.level.value,
                    "message": alert.message,
                    "current_usage": alert.current_usage,
                    "budget_limit": alert.budget_limit,
                    "usage_percent": alert.usage_percent,
                    "triggered_at": alert.triggered_at.isoformat(),
                }
                for alert in alerts
            ]
        finally:
            store.close()

    return router


def _get_dashboard_html() -> str:
    """Get the cost dashboard HTML."""
    return """<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>OCLAWMA Cost Dashboard</title>
    <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.1/dist/chart.umd.min.js"></script>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
            background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
            color: #e0e0e0;
            min-height: 100vh;
        }
        .container {
            max-width: 1400px;
            margin: 0 auto;
            padding: 20px;
        }
        header {
            background: rgba(255,255,255,0.05);
            backdrop-filter: blur(10px);
            border-radius: 16px;
            padding: 24px;
            margin-bottom: 24px;
            border: 1px solid rgba(255,255,255,0.1);
        }
        h1 {
            font-size: 28px;
            background: linear-gradient(90deg, #00d4ff, #7b2cbf);
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
            margin-bottom: 8px;
        }
        .subtitle {
            color: #888;
            font-size: 14px;
        }
        .stats-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
            gap: 20px;
            margin-bottom: 24px;
        }
        .stat-card {
            background: rgba(255,255,255,0.05);
            backdrop-filter: blur(10px);
            border-radius: 16px;
            padding: 20px;
            border: 1px solid rgba(255,255,255,0.1);
            transition: transform 0.2s;
        }
        .stat-card:hover {
            transform: translateY(-2px);
        }
        .stat-label {
            font-size: 12px;
            text-transform: uppercase;
            letter-spacing: 1px;
            color: #888;
            margin-bottom: 8px;
        }
        .stat-value {
            font-size: 32px;
            font-weight: 700;
            color: #fff;
        }
        .stat-change {
            font-size: 12px;
            margin-top: 4px;
        }
        .stat-change.positive { color: #4ade80; }
        .stat-change.negative { color: #f87171; }
        .section {
            background: rgba(255,255,255,0.05);
            backdrop-filter: blur(10px);
            border-radius: 16px;
            padding: 24px;
            margin-bottom: 24px;
            border: 1px solid rgba(255,255,255,0.1);
        }
        .section-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 20px;
        }
        .section-title {
            font-size: 18px;
            font-weight: 600;
        }
        .filters {
            display: flex;
            gap: 12px;
        }
        select, button {
            background: rgba(255,255,255,0.1);
            border: 1px solid rgba(255,255,255,0.2);
            color: #fff;
            padding: 8px 16px;
            border-radius: 8px;
            font-size: 14px;
            cursor: pointer;
        }
        select:hover, button:hover {
            background: rgba(255,255,255,0.15);
        }
        .chart-container {
            position: relative;
            height: 300px;
        }
        .budget-list {
            display: flex;
            flex-direction: column;
            gap: 16px;
        }
        .budget-item {
            background: rgba(255,255,255,0.03);
            border-radius: 12px;
            padding: 16px;
        }
        .budget-header {
            display: flex;
            justify-content: space-between;
            margin-bottom: 12px;
        }
        .budget-name {
            font-weight: 600;
        }
        .budget-limit {
            color: #888;
            font-size: 14px;
        }
        .progress-bar {
            height: 8px;
            background: rgba(255,255,255,0.1);
            border-radius: 4px;
            overflow: hidden;
            margin-bottom: 8px;
        }
        .progress-fill {
            height: 100%;
            border-radius: 4px;
            transition: width 0.3s ease;
        }
        .progress-fill.low { background: linear-gradient(90deg, #4ade80, #22c55e); }
        .progress-fill.medium { background: linear-gradient(90deg, #fbbf24, #f59e0b); }
        .progress-fill.high { background: linear-gradient(90deg, #f87171, #ef4444); }
        .budget-stats {
            display: flex;
            justify-content: space-between;
            font-size: 12px;
            color: #888;
        }
        .jobs-table {
            width: 100%;
            border-collapse: collapse;
        }
        .jobs-table th {
            text-align: left;
            padding: 12px;
            font-size: 12px;
            text-transform: uppercase;
            letter-spacing: 1px;
            color: #888;
            border-bottom: 1px solid rgba(255,255,255,0.1);
        }
        .jobs-table td {
            padding: 12px;
            border-bottom: 1px solid rgba(255,255,255,0.05);
        }
        .jobs-table tr:hover {
            background: rgba(255,255,255,0.03);
        }
        .job-id {
            font-family: monospace;
            font-size: 12px;
            color: #00d4ff;
        }
        .cost-badge {
            display: inline-block;
            padding: 4px 8px;
            border-radius: 4px;
            font-size: 12px;
            font-weight: 600;
        }
        .cost-badge.low { background: rgba(74, 222, 128, 0.2); color: #4ade80; }
        .cost-badge.medium { background: rgba(251, 191, 36, 0.2); color: #fbbf24; }
        .cost-badge.high { background: rgba(248, 113, 113, 0.2); color: #f87171; }
        .loading {
            display: flex;
            justify-content: center;
            align-items: center;
            height: 200px;
        }
        .spinner {
            width: 40px;
            height: 40px;
            border: 3px solid rgba(255,255,255,0.1);
            border-top-color: #00d4ff;
            border-radius: 50%;
            animation: spin 1s linear infinite;
        }
        @keyframes spin {
            to { transform: rotate(360deg); }
        }
        .refresh-btn {
            display: flex;
            align-items: center;
            gap: 8px;
        }
        .refresh-btn.spinning svg {
            animation: spin 1s linear infinite;
        }
    </style>
</head>
<body>
    <div class="container">
        <header>
            <h1>💰 Cost Dashboard</h1>
            <p class="subtitle">Track API costs, compute time, and storage usage</p>
        </header>

        <div class="stats-grid" id="statsGrid">
            <div class="stat-card">
                <div class="stat-label">Today's Cost</div>
                <div class="stat-value" id="dailyCost">-</div>
                <div class="stat-change" id="dailyJobs">- jobs</div>
            </div>
            <div class="stat-card">
                <div class="stat-label">Weekly Cost</div>
                <div class="stat-value" id="weeklyCost">-</div>
                <div class="stat-change" id="weeklyJobs">- jobs</div>
            </div>
            <div class="stat-card">
                <div class="stat-label">Monthly Cost</div>
                <div class="stat-value" id="monthlyCost">-</div>
                <div class="stat-change" id="monthlyJobs">- jobs</div>
            </div>
            <div class="stat-card">
                <div class="stat-label">Active Budgets</div>
                <div class="stat-value" id="activeBudgets">-</div>
                <div class="stat-change" id="budgetStatus">-</div>
            </div>
        </div>

        <div class="section">
            <div class="section-header">
                <h2 class="section-title">Cost Trends</h2>
                <div class="filters">
                    <select id="trendPeriod" onchange="loadTrends()">
                        <option value="daily">Daily</option>
                        <option value="weekly">Weekly</option>
                        <option value="monthly">Monthly</option>
                    </select>
                    <button class="refresh-btn" onclick="refreshAll()">
                        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                            <path d="M23 4v6h-6M1 20v-6h6M3.51 9a9 9 0 0114.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0020.49 15"/>
                        </svg>
                        Refresh
                    </button>
                </div>
            </div>
            <div class="chart-container">
                <canvas id="trendChart"></canvas>
            </div>
        </div>

        <div class="section">
            <div class="section-header">
                <h2 class="section-title">Cost Breakdown</h2>
            </div>
            <div class="chart-container">
                <canvas id="breakdownChart"></canvas>
            </div>
        </div>

        <div class="section">
            <div class="section-header">
                <h2 class="section-title">Budget Status</h2>
                <button onclick="createBudget()">+ New Budget</button>
            </div>
            <div class="budget-list" id="budgetList">
                <div class="loading"><div class="spinner"></div></div>
            </div>
        </div>

        <div class="section">
            <div class="section-header">
                <h2 class="section-title">Recent Jobs</h2>
                <select id="jobsLimit" onchange="loadJobs()">
                    <option value="10">10 jobs</option>
                    <option value="25">25 jobs</option>
                    <option value="50" selected>50 jobs</option>
                    <option value="100">100 jobs</option>
                </select>
            </div>
            <table class="jobs-table">
                <thead>
                    <tr>
                        <th>Job ID</th>
                        <th>Project</th>
                        <th>Created</th>
                        <th>API Cost</th>
                        <th>Total Cost</th>
                    </tr>
                </thead>
                <tbody id="jobsTableBody">
                    <tr><td colspan="5" class="loading"><div class="spinner"></div></td></tr>
                </tbody>
            </table>
        </div>
    </div>

    <script>
        // Chart instances
        let trendChart = null;
        let breakdownChart = null;

        // Initialize
        document.addEventListener('DOMContentLoaded', () => {
            refreshAll();
        });

        function refreshAll() {
            loadStats();
            loadTrends();
            loadBreakdown();
            loadBudgets();
            loadJobs();
        }

        async function loadStats() {
            try {
                const response = await fetch('/costs/api/stats');
                const data = await response.json();

                document.getElementById('dailyCost').textContent = '$' + data.daily.total_cost.toFixed(4);
                document.getElementById('dailyJobs').textContent = data.daily.total_jobs + ' jobs';

                document.getElementById('weeklyCost').textContent = '$' + data.weekly.total_cost.toFixed(4);
                document.getElementById('weeklyJobs').textContent = data.weekly.total_jobs + ' jobs';

                document.getElementById('monthlyCost').textContent = '$' + data.monthly.total_cost.toFixed(4);
                document.getElementById('monthlyJobs').textContent = data.monthly.total_jobs + ' jobs';

                document.getElementById('activeBudgets').textContent = data.budgets.length;

                const alerts = data.budgets.filter(b => b.percent >= 75).length;
                document.getElementById('budgetStatus').textContent = alerts > 0 ? alerts + ' alerts' : 'All healthy';
                document.getElementById('budgetStatus').className = 'stat-change ' + (alerts > 0 ? 'negative' : 'positive');
            } catch (error) {
                console.error('Failed to load stats:', error);
            }
        }

        async function loadTrends() {
            const period = document.getElementById('trendPeriod').value;
            try {
                const response = await fetch(`/costs/api/report?period=${period}`);
                const data = await response.json();

                const labels = Object.keys(data.daily_breakdown).sort();
                const values = labels.map(date => data.daily_breakdown[date]);

                const ctx = document.getElementById('trendChart').getContext('2d');

                if (trendChart) {
                    trendChart.destroy();
                }

                trendChart = new Chart(ctx, {
                    type: 'line',
                    data: {
                        labels: labels,
                        datasets: [{
                            label: 'Cost ($)',
                            data: values,
                            borderColor: '#00d4ff',
                            backgroundColor: 'rgba(0, 212, 255, 0.1)',
                            borderWidth: 2,
                            fill: true,
                            tension: 0.4
                        }]
                    },
                    options: {
                        responsive: true,
                        maintainAspectRatio: false,
                        plugins: {
                            legend: { display: false }
                        },
                        scales: {
                            y: {
                                beginAtZero: true,
                                grid: { color: 'rgba(255,255,255,0.1)' },
                                ticks: { color: '#888' }
                            },
                            x: {
                                grid: { display: false },
                                ticks: { color: '#888' }
                            }
                        }
                    }
                });
            } catch (error) {
                console.error('Failed to load trends:', error);
            }
        }

        async function loadBreakdown() {
            try {
                const response = await fetch('/costs/api/report?period=weekly');
                const data = await response.json();

                const ctx = document.getElementById('breakdownChart').getContext('2d');

                if (breakdownChart) {
                    breakdownChart.destroy();
                }

                const providers = Object.keys(data.costs_by_provider);
                const values = Object.values(data.costs_by_provider);

                breakdownChart = new Chart(ctx, {
                    type: 'doughnut',
                    data: {
                        labels: providers,
                        datasets: [{
                            data: values,
                            backgroundColor: [
                                '#00d4ff',
                                '#7b2cbf',
                                '#f59e0b',
                                '#ef4444',
                                '#10b981',
                                '#8b5cf6'
                            ]
                        }]
                    },
                    options: {
                        responsive: true,
                        maintainAspectRatio: false,
                        plugins: {
                            legend: {
                                position: 'right',
                                labels: { color: '#e0e0e0' }
                            }
                        }
                    }
                });
            } catch (error) {
                console.error('Failed to load breakdown:', error);
            }
        }

        async function loadBudgets() {
            try {
                const response = await fetch('/costs/api/budgets');
                const budgets = await response.json();

                const container = document.getElementById('budgetList');
                container.innerHTML = '';

                if (budgets.length === 0) {
                    container.innerHTML = '<p style="text-align: center; color: #888;">No budgets configured</p>';
                    return;
                }

                budgets.forEach(budget => {
                    const usage = budget.usage || { current: 0, percent: 0 };
                    const percent = usage.percent;
                    let statusClass = 'low';
                    if (percent >= 90) statusClass = 'high';
                    else if (percent >= 75) statusClass = 'medium';

                    const html = `
                        <div class="budget-item">
                            <div class="budget-header">
                                <span class="budget-name">${escapeHtml(budget.name)}</span>
                                <span class="budget-limit">$${usage.current.toFixed(2)} / $${budget.monthly_limit.toFixed(2)}</span>
                            </div>
                            <div class="progress-bar">
                                <div class="progress-fill ${statusClass}" style="width: ${Math.min(percent, 100)}%"></div>
                            </div>
                            <div class="budget-stats">
                                <span>${percent.toFixed(1)}% used</span>
                                <span>$${(budget.monthly_limit - usage.current).toFixed(2)} remaining</span>
                            </div>
                        </div>
                    `;
                    container.innerHTML += html;
                });
            } catch (error) {
                console.error('Failed to load budgets:', error);
                document.getElementById('budgetList').innerHTML =
                    '<p style="text-align: center; color: #f87171;">Failed to load budgets</p>';
            }
        }

        async function loadJobs() {
            const limit = document.getElementById('jobsLimit').value;
            try {
                const response = await fetch(`/costs/api/jobs?limit=${limit}`);
                const jobs = await response.json();

                const tbody = document.getElementById('jobsTableBody');
                tbody.innerHTML = '';

                jobs.forEach(job => {
                    const costClass = job.total_cost > 1 ? 'high' : (job.total_cost > 0.1 ? 'medium' : 'low');
                    const date = new Date(job.created_at).toLocaleString();

                    const html = `
                        <tr>
                            <td><span class="job-id">${escapeHtml(job.job_id.substring(0, 16))}...</span></td>
                            <td>${escapeHtml(job.project_id || '-')}</td>
                            <td>${date}</td>
                            <td>$${job.total_api_cost.toFixed(4)}</td>
                            <td><span class="cost-badge ${costClass}">$${job.total_cost.toFixed(4)}</span></td>
                        </tr>
                    `;
                    tbody.innerHTML += html;
                });
            } catch (error) {
                console.error('Failed to load jobs:', error);
                document.getElementById('jobsTableBody').innerHTML =
                    '<tr><td colspan="5" style="text-align: center; color: #f87171;">Failed to load jobs</td></tr>';
            }
        }

        function createBudget() {
            const name = prompt('Budget name:');
            if (!name) return;

            const limit = prompt('Monthly limit ($):');
            if (!limit || isNaN(parseFloat(limit))) return;

            fetch('/costs/api/budgets', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({
                    name: name,
                    monthly_limit: parseFloat(limit),
                    alert_thresholds: [50, 75, 90]
                })
            })
            .then(response => response.json())
            .then(() => {
                loadBudgets();
                loadStats();
            })
            .catch(error => {
                console.error('Failed to create budget:', error);
                alert('Failed to create budget');
            });
        }

        function escapeHtml(text) {
            if (!text) return '';
            const div = document.createElement('div');
            div.textContent = text;
            return div.innerHTML;
        }

        // Auto-refresh every 30 seconds
        setInterval(refreshAll, 30000);
    </script>
</body>
</html>
"""
