"""Reporting API endpoints for CSV and PDF export."""

from fastapi import APIRouter, HTTPException, Query, Body
from fastapi.responses import StreamingResponse
from typing import Optional, Dict, Any
from datetime import datetime
from sqlalchemy import select
import io
import csv
import tempfile
from pathlib import Path

from src.core.database import Trade, get_database

router = APIRouter()


def get_csv_exporter():
    """Get CSV exporter instance."""
    from src.reporting.csv_exporter import get_csv_exporter as _get_csv_exporter
    return _get_csv_exporter()


def get_pdf_generator():
    """Get PDF generator instance."""
    from src.reporting.pdf_generator import get_pdf_generator as _get_pdf_generator
    return _get_pdf_generator()


@router.post("/backtest/csv")
async def export_backtest_csv(
    results: Dict[str, Any] = Body(...),
):
    """Export backtest results as CSV."""
    try:
        output = io.StringIO()
        writer = csv.writer(output)
        
        # Write header
        writer.writerow(['Metric', 'Value'])
        
        # Write metrics
        writer.writerow(['Total Return', f"{(results.get('total_return', 0) * 100):.2f}%"])
        writer.writerow(['Sharpe Ratio', f"{results.get('sharpe_ratio', 0):.2f}"])
        writer.writerow(['Sortino Ratio', f"{results.get('sortino_ratio', 0):.2f}"])
        writer.writerow(['Max Drawdown', f"{(results.get('max_drawdown', 0) * 100):.2f}%"])
        writer.writerow(['Win Rate', f"{(results.get('win_rate', 0) * 100):.2f}%"])
        writer.writerow(['Total Trades', results.get('total_trades', 0)])
        writer.writerow(['Final Value', f"${results.get('final_value', 0):.2f}"])
        writer.writerow(['Initial Capital', f"${results.get('initial_capital', 0):.2f}"])
        
        # Write trades if available
        if results.get('trades'):
            writer.writerow([])
            writer.writerow(['Trades'])
            writer.writerow(['Timestamp', 'Side', 'Price', 'Quantity', 'Value'])
            for trade in results['trades']:
                writer.writerow([
                    trade.get('timestamp', ''),
                    trade.get('side', ''),
                    f"${trade.get('price', 0):.2f}",
                    trade.get('quantity', 0),
                    f"${(trade.get('price', 0) * trade.get('quantity', 0)):.2f}",
                ])
        
        output.seek(0)
        
        return StreamingResponse(
            iter([output.getvalue()]),
            media_type="text/csv",
            headers={"Content-Disposition": f"attachment; filename=backtest_results_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv"}
        )
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@router.post("/backtest/pdf")
async def export_backtest_pdf(
    results: Dict[str, Any] = Body(...),
):
    """Export backtest results as PDF."""
    try:
        pdf_generator = get_pdf_generator()
        
        # Create temporary file
        with tempfile.NamedTemporaryFile(delete=False, suffix='.pdf') as tmp_file:
            tmp_path = Path(tmp_file.name)
        
        # Convert results to metrics format expected by PDF generator
        metrics = {
            'total_return_percent': (results.get('total_return', 0) * 100),
            'sharpe_ratio': results.get('sharpe_ratio', 0),
            'sortino_ratio': results.get('sortino_ratio', 0),
            'max_drawdown': results.get('max_drawdown', 0),
            'win_rate': results.get('win_rate', 0),
        }
        
        # Generate PDF
        success = pdf_generator.generate_performance_report(
            tmp_path,
            metrics,
            "Backtest Report"
        )
        
        if not success:
            raise HTTPException(status_code=500, detail="Failed to generate PDF")
        
        # Read PDF and return as stream
        with open(tmp_path, 'rb') as f:
            pdf_content = f.read()
        
        # Clean up
        tmp_path.unlink()
        
        return StreamingResponse(
            io.BytesIO(pdf_content),
            media_type="application/pdf",
            headers={"Content-Disposition": f"attachment; filename=backtest_report_{datetime.now().strftime('%Y%m%d_%H%M%S')}.pdf"}
        )
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@router.get("/trades/csv")
async def export_trades_csv(
    start_date: Optional[str] = None,
    end_date: Optional[str] = None,
    paper_trading: bool = True,
):
    """Export trades as CSV."""
    try:
        csv_exporter = get_csv_exporter()
        
        # Parse dates if provided
        start = datetime.fromisoformat(start_date) if start_date else None
        end = datetime.fromisoformat(end_date) if end_date else None
        
        # Create temporary file
        with tempfile.NamedTemporaryFile(delete=False, suffix='.csv') as tmp_file:
            tmp_path = Path(tmp_file.name)
        
        # Export to file
        success = csv_exporter.export_trades(
            filepath=tmp_path,
            paper_trading=paper_trading,
            start_date=start,
            end_date=end
        )
        
        if not success:
            raise HTTPException(status_code=500, detail="Failed to export trades")
        
        # Read and return
        with open(tmp_path, 'r') as f:
            csv_content = f.read()
        
        tmp_path.unlink()
        
        return StreamingResponse(
            iter([csv_content]),
            media_type="text/csv",
            headers={"Content-Disposition": f"attachment; filename=trades_{datetime.now().strftime('%Y%m%d')}.csv"}
        )
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@router.get("/portfolio/csv")
async def export_portfolio_csv(
    paper_trading: bool = True,
):
    """Export portfolio as CSV."""
    try:
        csv_exporter = get_csv_exporter()
        
        # Create temporary file
        with tempfile.NamedTemporaryFile(delete=False, suffix='.csv') as tmp_file:
            tmp_path = Path(tmp_file.name)
        
        # Export to file
        success = csv_exporter.export_portfolio(filepath=tmp_path)
        
        if not success:
            raise HTTPException(status_code=500, detail="Failed to export portfolio")
        
        # Read and return
        with open(tmp_path, 'r') as f:
            csv_content = f.read()
        
        tmp_path.unlink()
        
        return StreamingResponse(
            iter([csv_content]),
            media_type="text/csv",
            headers={"Content-Disposition": f"attachment; filename=portfolio_{datetime.now().strftime('%Y%m%d')}.csv"}
        )
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@router.get("/tax/{method}")
async def generate_tax_report(
    method: str,  # fifo, lifo, specific_id
    symbol: Optional[str] = Query(None),
    year: Optional[int] = Query(None),
    paper_trading: bool = Query(True),
):
    """Generate tax report using specified method."""
    try:
        if year is None:
            year = datetime.now().year
        
        tax_reporter = get_tax_reporter()
        
        if method == "fifo":
            if symbol:
                events = tax_reporter.generate_fifo_report(symbol, year, paper_trading)
            else:
                # Generate for all symbols
                events = []
                # Get all symbols from trades
                db = get_database()
                async with db.get_session() as session:
                    stmt = select(Trade.symbol).distinct()
                    result = await session.execute(stmt)
                    symbols = result.scalars().all()
                    for sym in symbols:
                        events.extend(tax_reporter.generate_fifo_report(sym, year, paper_trading))
        elif method == "lifo":
            if symbol:
                events = tax_reporter.generate_lifo_report(symbol, year, paper_trading)
            else:
                events = []
                db = get_database()
                async with db.get_session() as session:
                    stmt = select(Trade.symbol).distinct()
                    result = await session.execute(stmt)
                    symbols = result.scalars().all()
                    for sym in symbols:
                        events.extend(tax_reporter.generate_lifo_report(sym, year, paper_trading))
        else:
            raise HTTPException(status_code=400, detail=f"Unsupported tax method: {method}")
        
        # Generate CSV
        output = io.StringIO()
        writer = csv.writer(output)
        writer.writerow(['Date', 'Symbol', 'Quantity', 'Cost Basis', 'Proceeds', 'Gain/Loss', 'Buy Date'])
        for event in events:
            writer.writerow([
                event.get('date', ''),
                event.get('symbol', ''),
                event.get('quantity', 0),
                event.get('cost_basis', 0),
                event.get('proceeds', 0),
                event.get('gain_loss', 0),
                event.get('buy_date', ''),
            ])
        output.seek(0)
        
        return StreamingResponse(
            iter([output.getvalue()]),
            media_type="text/csv",
            headers={"Content-Disposition": f"attachment; filename=tax_report_{method}_{year}_{datetime.now().strftime('%Y%m%d')}.csv"}
        )
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


def get_tax_reporter():
    """Get tax reporter instance."""
    from src.reporting.tax_reporter import get_tax_reporter as _get_tax_reporter
    return _get_tax_reporter()
