from datetime import datetime, timedelta
from typing import Any, Dict, List, Optional
import random  # Used for mock data generation - TODO: Replace with actual historical data

from app.services.report_store import ReportStore
from fastapi import APIRouter, HTTPException, Path, Query, status
from pydantic import BaseModel

router = APIRouter()


class DomainBase(BaseModel):
    """Base Domain schema"""

    name: str
    description: Optional[str] = None
    policy: Optional[str] = None


class DomainResponse(DomainBase):
    """Domain response schema"""

    reports_count: int = 0
    emails_count: int = 0
    compliance_rate: float = 0.0


class DomainStatsResponse(BaseModel):
    """Domain statistics for the domain details page"""

    complianceRate: float
    totalEmails: int
    failedEmails: int
    reportCount: int


class DNSRecordResponse(BaseModel):
    """DNS record information for a domain"""

    dmarc: bool
    dmarcRecord: Optional[str] = None
    spf: bool
    spfRecord: Optional[str] = None
    dkim: bool
    dkimSelectors: Optional[str] = None


class TimelinePoint(BaseModel):
    """Data point for compliance timeline"""

    date: str
    compliance_rate: float


class ReportEntry(BaseModel):
    """Summary of a DMARC report"""

    id: str
    org_name: str
    begin_date: int
    end_date: int
    total_emails: int
    pass_rate: float
    policy: str


class SourceEntry(BaseModel):
    """Summary of a sending source"""

    ip: str
    count: int
    spf: str
    dkim: str
    dmarc: str
    disposition: str


class DomainReportsResponse(BaseModel):
    """Domain reports with compliance timeline"""

    reports: List[ReportEntry]
    compliance_timeline: List[TimelinePoint]


class DomainSourcesResponse(BaseModel):
    """Domain sending sources"""

    sources: List[SourceEntry]


class DomainSummaryResponse(BaseModel):
    """Domain summary for dashboard"""

    total_domains: int
    total_emails: int
    overall_pass_rate: float
    reports_processed: int
    domains: List[Dict[str, Any]]


@router.get("/summary", response_model=DomainSummaryResponse)
async def get_domains_summary():
    """
    Get summary statistics for all domains, formatted for the dashboard.
    """
    store = ReportStore.get_instance()
    domains = store.get_domains()
    summaries = store.get_all_domain_summaries()

    # Calculate overall statistics
    total_domains = len(domains)
    total_emails = 0
    total_passed = 0
    total_reports = 0

    domains_list = []

    for domain_name in domains:
        summary = summaries.get(domain_name, {})
        total_emails += summary.get("total_count", 0)
        total_passed += summary.get("passed_count", 0)
        total_reports += summary.get("reports_processed", 0)

        # Format domain data for frontend
        domains_list.append(
            {
                "id": domain_name,  # Using the domain name as ID for now
                "domain_name": domain_name,
                "total_emails": summary.get("total_count", 0),
                "passed_count": summary.get("passed_count", 0),
                "failed_count": summary.get("failed_count", 0),
                "pass_rate": summary.get("compliance_rate", 0),
                "report_count": summary.get("reports_processed", 0),
            }
        )

    # Calculate overall pass rate
    overall_pass_rate = 0
    if total_emails > 0:
        overall_pass_rate = round((total_passed / total_emails) * 100, 1)

    return DomainSummaryResponse(
        total_domains=total_domains,
        total_emails=total_emails,
        overall_pass_rate=overall_pass_rate,
        reports_processed=total_reports,
        domains=domains_list,
    )


@router.get("/domains", response_model=List[DomainResponse])
async def read_domains():
    """
    Retrieve domains with their statistics.
    For Milestone 1, this simply returns domains from the in-memory store.
    """
    store = ReportStore.get_instance()
    domains = store.get_domains()
    summaries = store.get_all_domain_summaries()

    result = []
    for domain_name in domains:
        summary = summaries.get(domain_name, {})
        domain_response = DomainResponse(
            name=domain_name,
            policy=summary.get("policy", "unknown"),
            reports_count=summary.get("reports_processed", 0),
            emails_count=summary.get("total_count", 0),
            compliance_rate=summary.get("compliance_rate", 0.0),
        )
        result.append(domain_response)

    return result


@router.get("/domains/{domain_name}", response_model=DomainResponse)
async def read_domain(domain_name: str):
    """
    Get statistics for a specific domain.
    """
    store = ReportStore.get_instance()
    domains = store.get_domains()

    if domain_name not in domains:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Domain not found",
        )

    summary = store.get_domain_summary(domain_name)

    return DomainResponse(
        name=domain_name,
        policy=summary.get("policy", "unknown"),
        reports_count=summary.get("reports_processed", 0),
        emails_count=summary.get("total_count", 0),
        compliance_rate=summary.get("compliance_rate", 0.0),
    )


# New endpoints for domain details page


@router.get("/{domain_id}/stats", response_model=DomainStatsResponse)
async def get_domain_stats(domain_id: str = Path(..., title="The domain ID or name")):
    """
    Get detailed statistics for a specific domain
    """
    store = ReportStore.get_instance()
    domains = store.get_domains()

    # For Milestone 1, domain_id is simply the domain name
    if domain_id not in domains:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Domain not found",
        )

    summary = store.get_domain_summary(domain_id)
    total_count = summary.get("total_count", 0)
    passed_count = summary.get("passed_count", 0)
    failed_count = total_count - passed_count
    compliance_rate = summary.get("compliance_rate", 0.0)
    reports_processed = summary.get("reports_processed", 0)

    return DomainStatsResponse(
        complianceRate=compliance_rate,
        totalEmails=total_count,
        failedEmails=failed_count,
        reportCount=reports_processed,
    )


@router.get("/{domain_id}/dns", response_model=DNSRecordResponse)
async def get_domain_dns_records(domain_id: str = Path(..., title="The domain ID or name")):
    """
    Get DNS records for a specific domain. For Milestone 1,
    this returns mock data since DNS integration is part of a future milestone.
    """
    store = ReportStore.get_instance()
    domains = store.get_domains()

    if domain_id not in domains:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Domain not found",
        )

    # For Milestone 1, return mock DNS record data
    # In a future milestone, this will be replaced with actual DNS lookups
    return DNSRecordResponse(
        dmarc=True,
        dmarcRecord="v=DMARC1; p=none; rua=mailto:dmarc@example.com; ruf=mailto:forensic@example.com; pct=100",
        spf=True,
        spfRecord="v=spf1 include:_spf.google.com include:spf.protection.outlook.com -all",
        dkim=True,
        dkimSelectors="selector1, selector2",
    )


@router.get("/{domain_id}/reports", response_model=DomainReportsResponse)
async def get_domain_reports(
    domain_id: str = Path(..., title="The domain ID or name"),
    limit: int = Query(10, title="Maximum number of reports to return"),
):
    """
    Get recent DMARC reports for a specific domain, along with compliance timeline
    """
    store = ReportStore.get_instance()
    domains = store.get_domains()

    if domain_id not in domains:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Domain not found",
        )

    # Get reports for this domain
    reports = store.get_domain_reports(domain_id, limit=limit)

    # Generate report entries
    report_entries = []
    for report in reports:
        report_entries.append(
            ReportEntry(
                id=report.get("report_id", "unknown"),
                org_name=report.get("org_name", "Unknown Organization"),
                begin_date=report.get("begin_date", 0),
                end_date=report.get("end_date", 0),
                total_emails=report.get("total_count", 0),
                pass_rate=report.get("pass_rate", 0.0),
                policy=report.get("policy", "none"),
            )
        )

    # Generate compliance timeline (last 30 days)
    timeline = []
    for i in range(30, 0, -1):
        date = datetime.now() - timedelta(days=i)
        date_str = date.strftime("%Y-%m-%d")

        # TODO: Replace with actual historical data in future milestone
        # For now, generate mock data with variation for demonstration purposes
        compliance_rate = random.uniform(80, 100)  # nosec B311 - Mock data only

        timeline.append(TimelinePoint(date=date_str, compliance_rate=round(compliance_rate, 1)))

    return DomainReportsResponse(reports=report_entries, compliance_timeline=timeline)


@router.get("/{domain_id}/sources", response_model=DomainSourcesResponse)
async def get_domain_sources(
    domain_id: str = Path(..., title="The domain ID or name"),
    days: int = Query(30, title="Number of days to look back"),
):
    """
    Get sending sources for a specific domain
    """
    store = ReportStore.get_instance()
    domains = store.get_domains()

    if domain_id not in domains:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Domain not found",
        )

    # Get sending sources for this domain
    sources = store.get_domain_sources(domain_id, days=days)

    source_entries = []
    for source in sources:
        source_entries.append(
            SourceEntry(
                ip=source.get("source_ip", "unknown"),
                count=source.get("count", 0),
                spf=source.get("spf_result", "unknown"),
                dkim=source.get("dkim_result", "unknown"),
                dmarc=(
                    "pass"
                    if source.get("spf_result") == "pass" or source.get("dkim_result") == "pass"
                    else "fail"
                ),
                disposition=source.get("disposition", "none"),
            )
        )

    return DomainSourcesResponse(sources=source_entries)


@router.delete("/{domain_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_domain(domain_id: str = Path(..., title="The domain ID or name")):
    """
    Delete a domain and all associated data.
    This performs a full cleanup of all reports and records related to this domain.
    """
    store = ReportStore.get_instance()
    domains = store.get_domains()

    if domain_id not in domains:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Domain not found",
        )

    # Perform deletion with cleanup
    deleted = store.delete_domain_with_cleanup(domain_id)

    if not deleted:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Failed to delete domain",
        )

    # Return 204 No Content on success
    return None


@router.get("/search", response_model=List[DomainResponse])
async def search_domains(
    q: Optional[str] = Query(None, title="Search query for domain name or description"),
    policy: Optional[str] = Query(None, title="Filter by DMARC policy"),
    page: int = Query(1, title="Page number", ge=1),
    limit: int = Query(10, title="Number of domains per page", ge=1, le=100),
):
    """
    Search domains with filtering and pagination.
    This supports searching by domain name/description and filtering by DMARC policy.

    Args:
        q: Optional search query for domain name or description
        policy: Optional filter by DMARC policy (none, quarantine, reject)
        page: Page number (1-based)
        limit: Number of domains per page (max 100)
    """
    store = ReportStore.get_instance()
    domains = store.get_domains()
    summaries = store.get_all_domain_summaries()

    # Apply search filter if provided
    filtered_domains = []
    for domain_name in domains:
        summary = summaries.get(domain_name, {})

        # Skip domain if it doesn't match the search query
        if q and q.lower() not in domain_name.lower():
            continue

        # Skip domain if it doesn't match the policy filter
        if policy and summary.get("policy") != policy:
            continue

        # Domain passed all filters
        filtered_domains.append(
            {
                "name": domain_name,
                "description": "",  # No description in in-memory store
                "policy": summary.get("policy", "unknown"),
                "reports_count": summary.get("reports_processed", 0),
                "emails_count": summary.get("total_count", 0),
                "compliance_rate": summary.get("compliance_rate", 0.0),
            }
        )

    # Apply pagination
    start_idx = (page - 1) * limit
    end_idx = start_idx + limit
    paginated_domains = filtered_domains[start_idx:end_idx]

    return [DomainResponse(**domain) for domain in paginated_domains]
