"""
Performance Reporter - Period-over-period SEO performance reports
================================================================
Purpose: Generate executive summaries, trend analysis, tactical breakdowns,
         and target-vs-actual comparison from Ahrefs historical data.
Python: 3.10+
"""

import argparse
import asyncio
import json
import logging
import sys
from dataclasses import dataclass, field, asdict
from datetime import datetime, timedelta
from pathlib import Path
from typing import Any

import aiohttp

from base_client import BaseAsyncClient, config

logger = logging.getLogger(__name__)


# ---------------------------------------------------------------------------
# Data classes
# ---------------------------------------------------------------------------

@dataclass
class TrendData:
    """Single trend data point for a metric."""
    period: str
    value: float
    change_pct: float | None = None
    direction: str = "stable"  # up, down, stable


@dataclass
class WinConcern:
    """A notable win or concern from performance analysis."""
    category: str
    description: str
    impact: str = "medium"  # high, medium, low
    action: str = ""


@dataclass
class TargetProgress:
    """Target vs actual progress tracking."""
    kpi_name: str
    target: float
    actual: float
    progress_pct: float = 0.0

    def compute_progress(self) -> None:
        """Compute progress percentage toward target."""
        if self.target and self.target != 0:
            self.progress_pct = round((self.actual / self.target) * 100, 1)
        else:
            self.progress_pct = 0.0


@dataclass
class PerformanceReport:
    """Complete performance report."""
    url: str = ""
    period: str = "monthly"
    date_from: str = ""
    date_to: str = ""
    health_score: float = 0.0
    health_trend: str = "stable"
    trends: dict[str, list[TrendData]] = field(default_factory=dict)
    wins: list[WinConcern] = field(default_factory=list)
    concerns: list[WinConcern] = field(default_factory=list)
    executive_summary: dict[str, Any] = field(default_factory=dict)
    tactical_breakdown: dict[str, Any] = field(default_factory=dict)
    target_progress: list[TargetProgress] = field(default_factory=list)
    traffic_value_change: float = 0.0
    timestamp: str = ""
    errors: list[str] = field(default_factory=list)


# ---------------------------------------------------------------------------
# Period helpers
# ---------------------------------------------------------------------------

PERIOD_DAYS = {
    "monthly": 30,
    "quarterly": 90,
    "yearly": 365,
}


def get_date_range(
    period: str, date_from: str | None = None, date_to: str | None = None
) -> tuple[str, str]:
    """Compute date range from period or explicit dates."""
    if date_from and date_to:
        return date_from, date_to
    end = datetime.now()
    days = PERIOD_DAYS.get(period, 30)
    start = end - timedelta(days=days)
    return start.strftime("%Y-%m-%d"), end.strftime("%Y-%m-%d")


def get_previous_range(
    date_from: str, date_to: str
) -> tuple[str, str]:
    """Compute the previous period of equal length for comparison."""
    start = datetime.strptime(date_from, "%Y-%m-%d")
    end = datetime.strptime(date_to, "%Y-%m-%d")
    delta = end - start
    prev_end = start - timedelta(days=1)
    prev_start = prev_end - delta
    return prev_start.strftime("%Y-%m-%d"), prev_end.strftime("%Y-%m-%d")


# ---------------------------------------------------------------------------
# Performance Reporter
# ---------------------------------------------------------------------------

class PerformanceReporter(BaseAsyncClient):
    """Generate period-over-period SEO performance reports from Ahrefs."""

    AHREFS_BASE = "https://api.ahrefs.com/v3"

    def __init__(self, api_token: str | None = None):
        super().__init__(max_concurrent=3, requests_per_second=2.0)
        self.api_token = api_token or config.get_required("AHREFS_API_TOKEN")
        self.headers = {
            "Authorization": f"Bearer {self.api_token}",
            "Accept": "application/json",
        }

    async def _ahrefs_get(
        self, session: aiohttp.ClientSession, endpoint: str, params: dict
    ) -> dict:
        """Make an authenticated GET request to Ahrefs API."""
        url = f"{self.AHREFS_BASE}/{endpoint}"
        async with session.get(url, headers=self.headers, params=params) as resp:
            if resp.status != 200:
                text = await resp.text()
                self.logger.warning(f"Ahrefs {endpoint} returned {resp.status}: {text}")
                return {"error": f"HTTP {resp.status}", "detail": text}
            return await resp.json()

    # ----- Data collectors -----

    async def get_metrics_history(
        self,
        session: aiohttp.ClientSession,
        url: str,
        date_from: str,
        date_to: str,
    ) -> list[dict]:
        """Fetch historical metrics via site-explorer-metrics-history."""
        data = await self._ahrefs_get(
            session,
            "site-explorer/metrics-history",
            {
                "target": url,
                "mode": "domain",
                "date_from": date_from,
                "date_to": date_to,
            },
        )
        if "error" in data:
            self.logger.warning(f"Metrics history error: {data}")
            return []
        return data.get("metrics", data.get("data", []))

    async def get_dr_history(
        self,
        session: aiohttp.ClientSession,
        url: str,
        date_from: str,
        date_to: str,
    ) -> list[dict]:
        """Fetch domain rating history."""
        data = await self._ahrefs_get(
            session,
            "site-explorer/domain-rating-history",
            {
                "target": url,
                "date_from": date_from,
                "date_to": date_to,
            },
        )
        if "error" in data:
            return []
        return data.get("domain_rating_history", data.get("data", []))

    async def get_current_metrics(
        self, session: aiohttp.ClientSession, url: str
    ) -> dict:
        """Fetch current snapshot metrics."""
        data = await self._ahrefs_get(
            session,
            "site-explorer/metrics",
            {"target": url, "mode": "domain"},
        )
        if "error" in data:
            return {}
        return data.get("metrics", data)

    async def get_volume_history(
        self,
        session: aiohttp.ClientSession,
        url: str,
        date_from: str,
        date_to: str,
    ) -> list[dict]:
        """Fetch total search volume history."""
        data = await self._ahrefs_get(
            session,
            "site-explorer/total-search-volume-history",
            {
                "target": url,
                "date_from": date_from,
                "date_to": date_to,
            },
        )
        if "error" in data:
            return []
        return data.get("total_search_volume_history", data.get("data", []))

    # ----- Analysis methods -----

    def calculate_period_comparison(
        self, current_data: list[dict], previous_data: list[dict], metric_key: str
    ) -> list[TrendData]:
        """Compare metric values between current and previous period."""
        trends = []

        def avg_metric(data_list: list[dict], key: str) -> float:
            vals = []
            for entry in data_list:
                val = entry.get(key)
                if val is None:
                    organic = entry.get("organic", {})
                    val = organic.get(key)
                if val is not None:
                    vals.append(float(val))
            return sum(vals) / len(vals) if vals else 0.0

        current_avg = avg_metric(current_data, metric_key)
        previous_avg = avg_metric(previous_data, metric_key)

        change_pct = None
        direction = "stable"
        if previous_avg and previous_avg != 0:
            change_pct = round(((current_avg - previous_avg) / abs(previous_avg)) * 100, 2)
            if change_pct > 2.0:
                direction = "up"
            elif change_pct < -2.0:
                direction = "down"

        trends.append(TrendData(
            period=metric_key,
            value=round(current_avg, 2),
            change_pct=change_pct,
            direction=direction,
        ))
        return trends

    def identify_wins(
        self, current: dict, previous: dict
    ) -> list[WinConcern]:
        """Identify significant positive changes between periods."""
        wins = []
        metric_labels = {
            "traffic": "Organic Traffic",
            "cost": "Traffic Value",
            "keywords": "Keyword Count",
            "refdomains": "Referring Domains",
        }

        for key, label in metric_labels.items():
            curr_val = self._extract_metric(current, key)
            prev_val = self._extract_metric(previous, key)
            if prev_val and prev_val > 0 and curr_val > prev_val:
                change_pct = ((curr_val - prev_val) / prev_val) * 100
                if change_pct >= 5.0:
                    impact = "high" if change_pct >= 20 else ("medium" if change_pct >= 10 else "low")
                    wins.append(WinConcern(
                        category=label,
                        description=f"{label} increased by {change_pct:+.1f}% ({prev_val:,.0f} -> {curr_val:,.0f})",
                        impact=impact,
                        action=f"Continue current {label.lower()} strategy",
                    ))
        return wins

    def identify_concerns(
        self, current: dict, previous: dict
    ) -> list[WinConcern]:
        """Identify significant negative changes between periods."""
        concerns = []
        metric_labels = {
            "traffic": "Organic Traffic",
            "cost": "Traffic Value",
            "keywords": "Keyword Count",
            "refdomains": "Referring Domains",
        }

        for key, label in metric_labels.items():
            curr_val = self._extract_metric(current, key)
            prev_val = self._extract_metric(previous, key)
            if prev_val and prev_val > 0 and curr_val < prev_val:
                change_pct = ((curr_val - prev_val) / prev_val) * 100
                if change_pct <= -5.0:
                    impact = "high" if change_pct <= -20 else ("medium" if change_pct <= -10 else "low")
                    actions = {
                        "Organic Traffic": "Investigate traffic sources and algorithm updates",
                        "Traffic Value": "Review keyword targeting and content quality",
                        "Keyword Count": "Expand content coverage and optimize existing pages",
                        "Referring Domains": "Strengthen link building outreach campaigns",
                    }
                    concerns.append(WinConcern(
                        category=label,
                        description=f"{label} decreased by {change_pct:.1f}% ({prev_val:,.0f} -> {curr_val:,.0f})",
                        impact=impact,
                        action=actions.get(label, f"Review {label.lower()} strategy"),
                    ))
        return concerns

    def _extract_metric(self, data: dict, key: str) -> float:
        """Extract a metric value from nested Ahrefs response."""
        if key in data:
            return float(data[key])
        organic = data.get("organic", {})
        if key in organic:
            return float(organic[key])
        return 0.0

    def generate_executive_summary(
        self,
        wins: list[WinConcern],
        concerns: list[WinConcern],
        health_score: float,
        health_trend: str,
        traffic_value_change: float,
    ) -> dict[str, Any]:
        """Generate high-level executive summary."""
        summary = {
            "health_score": health_score,
            "health_trend": health_trend,
            "traffic_value_change_usd": round(traffic_value_change, 2),
            "total_wins": len(wins),
            "total_concerns": len(concerns),
            "top_wins": [
                {"category": w.category, "description": w.description, "impact": w.impact}
                for w in sorted(wins, key=lambda x: {"high": 0, "medium": 1, "low": 2}.get(x.impact, 3))[:5]
            ],
            "top_concerns": [
                {"category": c.category, "description": c.description, "impact": c.impact}
                for c in sorted(concerns, key=lambda x: {"high": 0, "medium": 1, "low": 2}.get(x.impact, 3))[:5]
            ],
            "overall_assessment": "",
        }

        if health_score >= 75:
            summary["overall_assessment"] = "Strong performance - focus on maintaining momentum"
        elif health_score >= 50:
            summary["overall_assessment"] = "Moderate performance - targeted improvements needed"
        else:
            summary["overall_assessment"] = "Needs attention - prioritize fundamental improvements"

        return summary

    def generate_tactical_breakdown(
        self, current: dict, wins: list[WinConcern], concerns: list[WinConcern]
    ) -> dict[str, Any]:
        """Generate actionable next steps per dimension."""
        breakdown = {
            "traffic": {
                "status": "needs_review",
                "actions": [],
            },
            "rankings": {
                "status": "needs_review",
                "actions": [],
            },
            "links": {
                "status": "needs_review",
                "actions": [],
            },
            "content": {
                "status": "needs_review",
                "actions": [],
            },
            "technical": {
                "status": "needs_review",
                "actions": [],
            },
        }

        traffic = self._extract_metric(current, "traffic")
        keywords = self._extract_metric(current, "keywords")
        refdomains = self._extract_metric(current, "refdomains")

        # Traffic actions
        if traffic > 0:
            breakdown["traffic"]["status"] = "active"
            breakdown["traffic"]["actions"].append("Monitor top landing pages for traffic drops")
            breakdown["traffic"]["actions"].append("Identify new keyword opportunities in adjacent topics")
        else:
            breakdown["traffic"]["actions"].append("Establish organic traffic baseline with content strategy")

        # Rankings actions
        if keywords > 0:
            breakdown["rankings"]["status"] = "active"
            breakdown["rankings"]["actions"].append(
                f"Optimize pages for {int(keywords)} tracked keywords"
            )
            breakdown["rankings"]["actions"].append("Target featured snippets for top-performing queries")
        else:
            breakdown["rankings"]["actions"].append("Begin keyword research and content mapping")

        # Links actions
        if refdomains > 0:
            breakdown["links"]["status"] = "active"
            breakdown["links"]["actions"].append("Analyze top referring domains for partnership opportunities")
            breakdown["links"]["actions"].append("Monitor for lost backlinks and reclaim valuable links")
        else:
            breakdown["links"]["actions"].append("Develop link acquisition strategy with digital PR")

        # Content actions
        breakdown["content"]["actions"].append("Audit content freshness and update older pages")
        breakdown["content"]["actions"].append("Identify content gaps using competitor analysis")

        # Technical actions
        breakdown["technical"]["actions"].append("Run technical SEO audit for crawl issues")
        breakdown["technical"]["actions"].append("Verify Core Web Vitals pass thresholds")

        # Enrich with win/concern context
        for w in wins:
            cat_lower = w.category.lower()
            if "traffic" in cat_lower and breakdown.get("traffic"):
                breakdown["traffic"]["status"] = "improving"
            if "keyword" in cat_lower and breakdown.get("rankings"):
                breakdown["rankings"]["status"] = "improving"
            if "domain" in cat_lower or "link" in cat_lower:
                breakdown["links"]["status"] = "improving"

        for c in concerns:
            cat_lower = c.category.lower()
            if "traffic" in cat_lower and breakdown.get("traffic"):
                breakdown["traffic"]["status"] = "declining"
                breakdown["traffic"]["actions"].insert(0, c.action)
            if "keyword" in cat_lower and breakdown.get("rankings"):
                breakdown["rankings"]["status"] = "declining"
                breakdown["rankings"]["actions"].insert(0, c.action)

        return breakdown

    def compare_targets(
        self, current: dict, targets: dict
    ) -> list[TargetProgress]:
        """Compare current metrics against saved targets."""
        progress_list = []
        for key, target_val in targets.items():
            parts = key.split(".")
            metric_name = parts[-1] if len(parts) > 1 else key
            actual = self._extract_metric(current, metric_name)
            if actual == 0.0 and len(parts) > 1:
                # Try alternate key resolution
                actual = current.get(key, 0.0)
                if isinstance(actual, dict):
                    actual = 0.0
            tp = TargetProgress(
                kpi_name=key,
                target=float(target_val),
                actual=float(actual),
            )
            tp.compute_progress()
            progress_list.append(tp)
        return progress_list

    # ----- Main orchestration -----

    async def report(
        self,
        url: str,
        period: str = "monthly",
        date_from: str | None = None,
        date_to: str | None = None,
        executive_only: bool = False,
        targets_path: str | None = None,
    ) -> PerformanceReport:
        """Orchestrate full performance report generation."""
        report = PerformanceReport(
            url=url,
            period=period,
            timestamp=datetime.now().isoformat(),
        )

        # Determine date ranges
        report.date_from, report.date_to = get_date_range(period, date_from, date_to)
        prev_from, prev_to = get_previous_range(report.date_from, report.date_to)

        async with aiohttp.ClientSession() as session:
            # Fetch current and previous period data concurrently
            tasks = [
                self.get_metrics_history(session, url, report.date_from, report.date_to),
                self.get_metrics_history(session, url, prev_from, prev_to),
                self.get_current_metrics(session, url),
                self.get_dr_history(session, url, report.date_from, report.date_to),
                self.get_volume_history(session, url, report.date_from, report.date_to),
            ]
            results = await asyncio.gather(*tasks, return_exceptions=True)

            current_history = results[0] if not isinstance(results[0], Exception) else []
            previous_history = results[1] if not isinstance(results[1], Exception) else []
            current_snapshot = results[2] if not isinstance(results[2], Exception) else {}
            dr_history = results[3] if not isinstance(results[3], Exception) else []
            volume_history = results[4] if not isinstance(results[4], Exception) else []

            for i, r in enumerate(results):
                if isinstance(r, Exception):
                    report.errors.append(f"Data fetch error [{i}]: {r}")

        # Calculate trends for key metrics
        for metric_key in ["traffic", "keywords", "cost", "refdomains"]:
            if current_history or previous_history:
                trend = self.calculate_period_comparison(
                    current_history if isinstance(current_history, list) else [],
                    previous_history if isinstance(previous_history, list) else [],
                    metric_key,
                )
                report.trends[metric_key] = [asdict(t) for t in trend]

        # Build previous snapshot for comparison
        previous_snapshot = {}
        if isinstance(previous_history, list) and previous_history:
            for entry in previous_history:
                for key in ("traffic", "cost", "keywords", "refdomains"):
                    val = entry.get(key)
                    if val is None:
                        organic = entry.get("organic", {})
                        val = organic.get(key)
                    if val is not None:
                        if key not in previous_snapshot:
                            previous_snapshot[key] = []
                        previous_snapshot[key].append(float(val))
            # Average the values
            previous_snapshot = {
                k: sum(v) / len(v) for k, v in previous_snapshot.items() if v
            }

        # Identify wins and concerns
        if isinstance(current_snapshot, dict):
            report.wins = self.identify_wins(current_snapshot, previous_snapshot)
            report.concerns = self.identify_concerns(current_snapshot, previous_snapshot)
        else:
            report.wins = []
            report.concerns = []

        # Calculate health score (simple heuristic)
        traffic = self._extract_metric(current_snapshot, "traffic") if isinstance(current_snapshot, dict) else 0
        keywords = self._extract_metric(current_snapshot, "keywords") if isinstance(current_snapshot, dict) else 0
        score_components = []
        if traffic > 0:
            score_components.append(min(100, traffic / 100))
        if keywords > 0:
            score_components.append(min(100, keywords / 50))
        if dr_history:
            latest_dr = dr_history[-1] if isinstance(dr_history, list) else {}
            dr_val = latest_dr.get("domain_rating", latest_dr.get("domainRating", 0))
            score_components.append(float(dr_val))
        report.health_score = round(
            sum(score_components) / max(len(score_components), 1), 1
        )

        # Health trend
        win_count = len(report.wins)
        concern_count = len(report.concerns)
        if win_count > concern_count:
            report.health_trend = "improving"
        elif concern_count > win_count:
            report.health_trend = "declining"
        else:
            report.health_trend = "stable"

        # Traffic value change
        curr_cost = self._extract_metric(current_snapshot, "cost") if isinstance(current_snapshot, dict) else 0
        prev_cost = previous_snapshot.get("cost", 0)
        report.traffic_value_change = round((curr_cost - prev_cost) / 100.0, 2)

        # Executive summary
        report.executive_summary = self.generate_executive_summary(
            report.wins, report.concerns,
            report.health_score, report.health_trend,
            report.traffic_value_change,
        )

        if not executive_only:
            # Tactical breakdown
            report.tactical_breakdown = self.generate_tactical_breakdown(
                current_snapshot if isinstance(current_snapshot, dict) else {},
                report.wins, report.concerns,
            )

            # Target comparison
            if targets_path:
                try:
                    targets_data = json.loads(Path(targets_path).read_text())
                    # Use 30-day targets by default
                    target_set = targets_data.get("30_day", targets_data)
                    report.target_progress = self.compare_targets(
                        current_snapshot if isinstance(current_snapshot, dict) else {},
                        target_set,
                    )
                except Exception as exc:
                    report.errors.append(f"Targets load error: {exc}")

        return report


# ---------------------------------------------------------------------------
# Output formatting
# ---------------------------------------------------------------------------

def format_text_report(report: PerformanceReport) -> str:
    """Format performance report as human-readable text."""
    lines = []
    lines.append("=" * 60)
    lines.append(f"SEO Performance Report: {report.url}")
    lines.append(f"Period: {report.period} ({report.date_from} to {report.date_to})")
    lines.append(f"Generated: {report.timestamp}")
    lines.append("=" * 60)

    # Executive Summary
    lines.append("\nEXECUTIVE SUMMARY")
    lines.append("-" * 40)
    es = report.executive_summary
    lines.append(f"  Health Score: {es.get('health_score', 0)}/100")
    trend_arrow = {"improving": "^", "declining": "v", "stable": "="}.get(
        es.get("health_trend", "stable"), "="
    )
    lines.append(f"  Trend: {trend_arrow} {es.get('health_trend', 'stable')}")
    lines.append(f"  Traffic Value Change: ${es.get('traffic_value_change_usd', 0):,.2f}")
    lines.append(f"  Assessment: {es.get('overall_assessment', 'N/A')}")

    # Wins
    lines.append(f"\n  Top Wins ({es.get('total_wins', 0)} total):")
    for w in es.get("top_wins", []):
        impact_marker = {"high": "!!!", "medium": "!!", "low": "!"}.get(w.get("impact", "low"), "!")
        lines.append(f"    {impact_marker} [{w.get('category', '')}] {w.get('description', '')}")

    # Concerns
    lines.append(f"\n  Top Concerns ({es.get('total_concerns', 0)} total):")
    for c in es.get("top_concerns", []):
        impact_marker = {"high": "!!!", "medium": "!!", "low": "!"}.get(c.get("impact", "low"), "!")
        lines.append(f"    {impact_marker} [{c.get('category', '')}] {c.get('description', '')}")

    # Trends
    if report.trends:
        lines.append("\nTRENDS")
        lines.append("-" * 40)
        for metric_name, trend_list in report.trends.items():
            for t in trend_list:
                if isinstance(t, dict):
                    dir_arrow = {"up": "^", "down": "v", "stable": "="}.get(
                        t.get("direction", "stable"), "="
                    )
                    change_str = f" ({t.get('change_pct', 0):+.1f}%)" if t.get("change_pct") is not None else ""
                    lines.append(f"  {dir_arrow} {metric_name}: {t.get('value', 0):,.2f}{change_str}")

    # Tactical Breakdown
    if report.tactical_breakdown:
        lines.append("\nTACTICAL BREAKDOWN")
        lines.append("-" * 40)
        for dim_name, dim_data in report.tactical_breakdown.items():
            status = dim_data.get("status", "unknown")
            status_marker = {
                "improving": "^", "declining": "v", "active": "=", "needs_review": "?"
            }.get(status, "?")
            lines.append(f"\n  [{dim_name.upper()}] Status: {status_marker} {status}")
            for action in dim_data.get("actions", [])[:3]:
                lines.append(f"    > {action}")

    # Target Progress
    if report.target_progress:
        lines.append("\nTARGET PROGRESS")
        lines.append("-" * 40)
        for tp in report.target_progress:
            if isinstance(tp, TargetProgress):
                bar_filled = int(min(tp.progress_pct, 100) / 5)
                bar = "#" * bar_filled + "-" * (20 - bar_filled)
                lines.append(
                    f"  {tp.kpi_name}: [{bar}] {tp.progress_pct:.0f}% "
                    f"(actual: {tp.actual:,.0f} / target: {tp.target:,.0f})"
                )

    # Errors
    if report.errors:
        lines.append("\nERRORS")
        lines.append("-" * 40)
        for err in report.errors:
            lines.append(f"  ! {err}")

    lines.append("\n" + "=" * 60)
    return "\n".join(lines)


def serialize_report(report: PerformanceReport) -> dict:
    """Serialize PerformanceReport to JSON-safe dictionary."""
    data = {
        "url": report.url,
        "period": report.period,
        "date_from": report.date_from,
        "date_to": report.date_to,
        "health_score": report.health_score,
        "health_trend": report.health_trend,
        "trends": report.trends,
        "wins": [asdict(w) for w in report.wins],
        "concerns": [asdict(c) for c in report.concerns],
        "executive_summary": report.executive_summary,
        "tactical_breakdown": report.tactical_breakdown,
        "target_progress": [asdict(tp) for tp in report.target_progress],
        "traffic_value_change": report.traffic_value_change,
        "timestamp": report.timestamp,
        "errors": report.errors,
    }
    return data


# ---------------------------------------------------------------------------
# CLI entry point
# ---------------------------------------------------------------------------

def parse_args() -> argparse.Namespace:
    """Parse command-line arguments."""
    parser = argparse.ArgumentParser(
        description="SEO Performance Reporter - Period-over-period analysis"
    )
    parser.add_argument(
        "--url", required=True, help="Target URL or domain"
    )
    parser.add_argument(
        "--period", choices=["monthly", "quarterly", "yearly", "custom"],
        default="monthly", help="Report period (default: monthly)"
    )
    parser.add_argument(
        "--from", dest="date_from", type=str, default=None,
        help="Start date (YYYY-MM-DD) for custom period"
    )
    parser.add_argument(
        "--to", dest="date_to", type=str, default=None,
        help="End date (YYYY-MM-DD) for custom period"
    )
    parser.add_argument(
        "--executive", action="store_true",
        help="Generate executive summary only"
    )
    parser.add_argument(
        "--targets", type=str, default=None,
        help="Path to targets JSON file for progress comparison"
    )
    parser.add_argument(
        "--json", action="store_true",
        help="Output results as JSON"
    )
    parser.add_argument(
        "--output", type=str, default=None,
        help="Save output to file path"
    )
    return parser.parse_args()


async def main() -> None:
    """Main entry point."""
    args = parse_args()

    reporter = PerformanceReporter()
    result = await reporter.report(
        url=args.url,
        period=args.period,
        date_from=args.date_from,
        date_to=args.date_to,
        executive_only=args.executive,
        targets_path=args.targets,
    )

    if args.json:
        output = json.dumps(serialize_report(result), indent=2, ensure_ascii=False)
    else:
        output = format_text_report(result)

    if args.output:
        Path(args.output).write_text(output, encoding="utf-8")
        logger.info(f"Output saved to {args.output}")
    else:
        print(output)

    reporter.print_stats()


if __name__ == "__main__":
    asyncio.run(main())
