"""Portfolio API routes."""
from datetime import datetime
from typing import Optional, List
from fastapi import APIRouter, Depends, HTTPException, status, Query
from pydantic import BaseModel, Field
from sqlalchemy import select, func, and_
from sqlalchemy.ext.asyncio import AsyncSession

from app.database import get_db
from app.routes.auth import get_current_user
from app.models.user import User
from app.models.portfolio import PortfolioDomain, DomainValuation
from app.services.valuation import valuation_service

router = APIRouter(prefix="/portfolio", tags=["portfolio"])


# ============== Schemas ==============

class PortfolioDomainCreate(BaseModel):
    """Schema for creating a portfolio domain."""
    domain: str = Field(..., min_length=3, max_length=255)
    purchase_date: Optional[datetime] = None
    purchase_price: Optional[float] = Field(None, ge=0)
    purchase_registrar: Optional[str] = None
    registrar: Optional[str] = None
    renewal_date: Optional[datetime] = None
    renewal_cost: Optional[float] = Field(None, ge=0)
    auto_renew: bool = True
    notes: Optional[str] = None
    tags: Optional[str] = None


class PortfolioDomainUpdate(BaseModel):
    """Schema for updating a portfolio domain."""
    purchase_date: Optional[datetime] = None
    purchase_price: Optional[float] = Field(None, ge=0)
    purchase_registrar: Optional[str] = None
    registrar: Optional[str] = None
    renewal_date: Optional[datetime] = None
    renewal_cost: Optional[float] = Field(None, ge=0)
    auto_renew: Optional[bool] = None
    status: Optional[str] = None
    notes: Optional[str] = None
    tags: Optional[str] = None


class PortfolioDomainSell(BaseModel):
    """Schema for marking a domain as sold."""
    sale_date: datetime
    sale_price: float = Field(..., ge=0)


class PortfolioDomainResponse(BaseModel):
    """Response schema for portfolio domain."""
    id: int
    domain: str
    purchase_date: Optional[datetime]
    purchase_price: Optional[float]
    purchase_registrar: Optional[str]
    registrar: Optional[str]
    renewal_date: Optional[datetime]
    renewal_cost: Optional[float]
    auto_renew: bool
    estimated_value: Optional[float]
    value_updated_at: Optional[datetime]
    is_sold: bool
    sale_date: Optional[datetime]
    sale_price: Optional[float]
    status: str
    notes: Optional[str]
    tags: Optional[str]
    roi: Optional[float]
    created_at: datetime
    updated_at: datetime
    
    class Config:
        from_attributes = True


class PortfolioSummary(BaseModel):
    """Summary of user's portfolio."""
    total_domains: int
    active_domains: int
    sold_domains: int
    total_invested: float
    total_value: float
    total_sold_value: float
    unrealized_profit: float
    realized_profit: float
    overall_roi: float


class ValuationResponse(BaseModel):
    """Response schema for domain valuation."""
    domain: str
    estimated_value: float
    currency: str
    scores: dict
    factors: dict
    confidence: str
    source: str
    calculated_at: str


# ============== Portfolio Endpoints ==============

@router.get("", response_model=List[PortfolioDomainResponse])
async def get_portfolio(
    status: Optional[str] = Query(None, description="Filter by status"),
    sort_by: str = Query("created_at", description="Sort field"),
    sort_order: str = Query("desc", description="Sort order (asc/desc)"),
    limit: int = Query(100, le=500),
    offset: int = Query(0, ge=0),
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """Get user's portfolio domains."""
    query = select(PortfolioDomain).where(PortfolioDomain.user_id == current_user.id)
    
    # Filter by status
    if status:
        query = query.where(PortfolioDomain.status == status)
    
    # Sorting
    sort_column = getattr(PortfolioDomain, sort_by, PortfolioDomain.created_at)
    if sort_order == "asc":
        query = query.order_by(sort_column.asc())
    else:
        query = query.order_by(sort_column.desc())
    
    # Pagination
    query = query.offset(offset).limit(limit)
    
    result = await db.execute(query)
    domains = result.scalars().all()
    
    # Calculate ROI for each domain
    responses = []
    for d in domains:
        response = PortfolioDomainResponse(
            id=d.id,
            domain=d.domain,
            purchase_date=d.purchase_date,
            purchase_price=d.purchase_price,
            purchase_registrar=d.purchase_registrar,
            registrar=d.registrar,
            renewal_date=d.renewal_date,
            renewal_cost=d.renewal_cost,
            auto_renew=d.auto_renew,
            estimated_value=d.estimated_value,
            value_updated_at=d.value_updated_at,
            is_sold=d.is_sold,
            sale_date=d.sale_date,
            sale_price=d.sale_price,
            status=d.status,
            notes=d.notes,
            tags=d.tags,
            roi=d.roi,
            created_at=d.created_at,
            updated_at=d.updated_at,
        )
        responses.append(response)
    
    return responses


@router.get("/summary", response_model=PortfolioSummary)
async def get_portfolio_summary(
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """Get portfolio summary statistics."""
    result = await db.execute(
        select(PortfolioDomain).where(PortfolioDomain.user_id == current_user.id)
    )
    domains = result.scalars().all()
    
    total_domains = len(domains)
    active_domains = sum(1 for d in domains if d.status == "active" and not d.is_sold)
    sold_domains = sum(1 for d in domains if d.is_sold)
    
    total_invested = sum(d.purchase_price or 0 for d in domains)
    total_value = sum(d.estimated_value or 0 for d in domains if not d.is_sold)
    total_sold_value = sum(d.sale_price or 0 for d in domains if d.is_sold)
    
    # Calculate active investment for ROI
    active_investment = sum(d.purchase_price or 0 for d in domains if not d.is_sold)
    sold_investment = sum(d.purchase_price or 0 for d in domains if d.is_sold)
    
    unrealized_profit = total_value - active_investment
    realized_profit = total_sold_value - sold_investment
    
    overall_roi = 0.0
    if total_invested > 0:
        overall_roi = ((total_value + total_sold_value - total_invested) / total_invested) * 100
    
    return PortfolioSummary(
        total_domains=total_domains,
        active_domains=active_domains,
        sold_domains=sold_domains,
        total_invested=round(total_invested, 2),
        total_value=round(total_value, 2),
        total_sold_value=round(total_sold_value, 2),
        unrealized_profit=round(unrealized_profit, 2),
        realized_profit=round(realized_profit, 2),
        overall_roi=round(overall_roi, 2),
    )


@router.post("", response_model=PortfolioDomainResponse, status_code=status.HTTP_201_CREATED)
async def add_portfolio_domain(
    data: PortfolioDomainCreate,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """Add a domain to portfolio."""
    # Check if domain already exists in user's portfolio
    existing = await db.execute(
        select(PortfolioDomain).where(
            and_(
                PortfolioDomain.user_id == current_user.id,
                PortfolioDomain.domain == data.domain.lower(),
            )
        )
    )
    if existing.scalar_one_or_none():
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Domain already in portfolio",
        )
    
    # Get initial valuation
    valuation = await valuation_service.estimate_value(data.domain, db, save_result=True)
    estimated_value = valuation.get("estimated_value") if "error" not in valuation else None
    
    # Create portfolio entry
    domain = PortfolioDomain(
        user_id=current_user.id,
        domain=data.domain.lower(),
        purchase_date=data.purchase_date,
        purchase_price=data.purchase_price,
        purchase_registrar=data.purchase_registrar,
        registrar=data.registrar or data.purchase_registrar,
        renewal_date=data.renewal_date,
        renewal_cost=data.renewal_cost,
        auto_renew=data.auto_renew,
        estimated_value=estimated_value,
        value_updated_at=datetime.utcnow() if estimated_value else None,
        notes=data.notes,
        tags=data.tags,
    )
    
    db.add(domain)
    await db.commit()
    await db.refresh(domain)
    
    return PortfolioDomainResponse(
        id=domain.id,
        domain=domain.domain,
        purchase_date=domain.purchase_date,
        purchase_price=domain.purchase_price,
        purchase_registrar=domain.purchase_registrar,
        registrar=domain.registrar,
        renewal_date=domain.renewal_date,
        renewal_cost=domain.renewal_cost,
        auto_renew=domain.auto_renew,
        estimated_value=domain.estimated_value,
        value_updated_at=domain.value_updated_at,
        is_sold=domain.is_sold,
        sale_date=domain.sale_date,
        sale_price=domain.sale_price,
        status=domain.status,
        notes=domain.notes,
        tags=domain.tags,
        roi=domain.roi,
        created_at=domain.created_at,
        updated_at=domain.updated_at,
    )


@router.get("/{domain_id}", response_model=PortfolioDomainResponse)
async def get_portfolio_domain(
    domain_id: int,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """Get a specific portfolio domain."""
    result = await db.execute(
        select(PortfolioDomain).where(
            and_(
                PortfolioDomain.id == domain_id,
                PortfolioDomain.user_id == current_user.id,
            )
        )
    )
    domain = result.scalar_one_or_none()
    
    if not domain:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Domain not found in portfolio",
        )
    
    return PortfolioDomainResponse(
        id=domain.id,
        domain=domain.domain,
        purchase_date=domain.purchase_date,
        purchase_price=domain.purchase_price,
        purchase_registrar=domain.purchase_registrar,
        registrar=domain.registrar,
        renewal_date=domain.renewal_date,
        renewal_cost=domain.renewal_cost,
        auto_renew=domain.auto_renew,
        estimated_value=domain.estimated_value,
        value_updated_at=domain.value_updated_at,
        is_sold=domain.is_sold,
        sale_date=domain.sale_date,
        sale_price=domain.sale_price,
        status=domain.status,
        notes=domain.notes,
        tags=domain.tags,
        roi=domain.roi,
        created_at=domain.created_at,
        updated_at=domain.updated_at,
    )


@router.put("/{domain_id}", response_model=PortfolioDomainResponse)
async def update_portfolio_domain(
    domain_id: int,
    data: PortfolioDomainUpdate,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """Update a portfolio domain."""
    result = await db.execute(
        select(PortfolioDomain).where(
            and_(
                PortfolioDomain.id == domain_id,
                PortfolioDomain.user_id == current_user.id,
            )
        )
    )
    domain = result.scalar_one_or_none()
    
    if not domain:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Domain not found in portfolio",
        )
    
    # Update fields
    update_data = data.model_dump(exclude_unset=True)
    for field, value in update_data.items():
        setattr(domain, field, value)
    
    await db.commit()
    await db.refresh(domain)
    
    return PortfolioDomainResponse(
        id=domain.id,
        domain=domain.domain,
        purchase_date=domain.purchase_date,
        purchase_price=domain.purchase_price,
        purchase_registrar=domain.purchase_registrar,
        registrar=domain.registrar,
        renewal_date=domain.renewal_date,
        renewal_cost=domain.renewal_cost,
        auto_renew=domain.auto_renew,
        estimated_value=domain.estimated_value,
        value_updated_at=domain.value_updated_at,
        is_sold=domain.is_sold,
        sale_date=domain.sale_date,
        sale_price=domain.sale_price,
        status=domain.status,
        notes=domain.notes,
        tags=domain.tags,
        roi=domain.roi,
        created_at=domain.created_at,
        updated_at=domain.updated_at,
    )


@router.post("/{domain_id}/sell", response_model=PortfolioDomainResponse)
async def mark_domain_sold(
    domain_id: int,
    data: PortfolioDomainSell,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """Mark a domain as sold."""
    result = await db.execute(
        select(PortfolioDomain).where(
            and_(
                PortfolioDomain.id == domain_id,
                PortfolioDomain.user_id == current_user.id,
            )
        )
    )
    domain = result.scalar_one_or_none()
    
    if not domain:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Domain not found in portfolio",
        )
    
    domain.is_sold = True
    domain.sale_date = data.sale_date
    domain.sale_price = data.sale_price
    domain.status = "sold"
    
    await db.commit()
    await db.refresh(domain)
    
    return PortfolioDomainResponse(
        id=domain.id,
        domain=domain.domain,
        purchase_date=domain.purchase_date,
        purchase_price=domain.purchase_price,
        purchase_registrar=domain.purchase_registrar,
        registrar=domain.registrar,
        renewal_date=domain.renewal_date,
        renewal_cost=domain.renewal_cost,
        auto_renew=domain.auto_renew,
        estimated_value=domain.estimated_value,
        value_updated_at=domain.value_updated_at,
        is_sold=domain.is_sold,
        sale_date=domain.sale_date,
        sale_price=domain.sale_price,
        status=domain.status,
        notes=domain.notes,
        tags=domain.tags,
        roi=domain.roi,
        created_at=domain.created_at,
        updated_at=domain.updated_at,
    )


@router.delete("/{domain_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_portfolio_domain(
    domain_id: int,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """Delete a domain from portfolio."""
    result = await db.execute(
        select(PortfolioDomain).where(
            and_(
                PortfolioDomain.id == domain_id,
                PortfolioDomain.user_id == current_user.id,
            )
        )
    )
    domain = result.scalar_one_or_none()
    
    if not domain:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Domain not found in portfolio",
        )
    
    await db.delete(domain)
    await db.commit()


@router.post("/{domain_id}/refresh-value", response_model=PortfolioDomainResponse)
async def refresh_domain_value(
    domain_id: int,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """Refresh the estimated value of a portfolio domain."""
    result = await db.execute(
        select(PortfolioDomain).where(
            and_(
                PortfolioDomain.id == domain_id,
                PortfolioDomain.user_id == current_user.id,
            )
        )
    )
    domain = result.scalar_one_or_none()
    
    if not domain:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Domain not found in portfolio",
        )
    
    # Get new valuation
    valuation = await valuation_service.estimate_value(domain.domain, db, save_result=True)
    
    if "error" not in valuation:
        domain.estimated_value = valuation["estimated_value"]
        domain.value_updated_at = datetime.utcnow()
        await db.commit()
        await db.refresh(domain)
    
    return PortfolioDomainResponse(
        id=domain.id,
        domain=domain.domain,
        purchase_date=domain.purchase_date,
        purchase_price=domain.purchase_price,
        purchase_registrar=domain.purchase_registrar,
        registrar=domain.registrar,
        renewal_date=domain.renewal_date,
        renewal_cost=domain.renewal_cost,
        auto_renew=domain.auto_renew,
        estimated_value=domain.estimated_value,
        value_updated_at=domain.value_updated_at,
        is_sold=domain.is_sold,
        sale_date=domain.sale_date,
        sale_price=domain.sale_price,
        status=domain.status,
        notes=domain.notes,
        tags=domain.tags,
        roi=domain.roi,
        created_at=domain.created_at,
        updated_at=domain.updated_at,
    )


# ============== Valuation Endpoints ==============

@router.get("/valuation/{domain}", response_model=ValuationResponse)
async def get_domain_valuation(
    domain: str,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """Get estimated value for any domain."""
    valuation = await valuation_service.estimate_value(domain, db, save_result=True)
    
    if "error" in valuation:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=valuation["error"],
        )
    
    return ValuationResponse(**valuation)

