#!/usr/bin/env python3
"""
Google Ads Agency Agent - Daily Health Check
Run automatically each morning to catch issues early.
"""

import sys
import argparse
from datetime import datetime, timedelta
from typing import List, Tuple

from core import (
    get_client, get_thresholds, ACCOUNTS, run_query,
    micros_to_currency, format_currency, format_percent,
    Issue, Severity, yesterday_date,
)


def check_conversion_tracking(client, account_key: str) -> List[Issue]:
    """Check if conversion tracking is working."""
    account = ACCOUNTS[account_key]
    issues = []
    
    # Check yesterday's conversions vs 7-day average
    yesterday = yesterday_date()
    query_yesterday = f"""
        SELECT
            metrics.conversions,
            metrics.cost_micros
        FROM campaign
        WHERE segments.date = '{yesterday}'
          AND campaign.status = 'ENABLED'
    """
    
    query_week = """
        SELECT
            metrics.conversions,
            metrics.cost_micros
        FROM campaign
        WHERE segments.date DURING LAST_7_DAYS
          AND campaign.status = 'ENABLED'
    """
    
    yesterday_results = run_query(client, account['id'], query_yesterday)
    week = run_query(client, account['id'], query_week)
    
    yesterday_conv = sum(r.metrics.conversions for r in yesterday_results)
    yesterday_cost = sum(micros_to_currency(r.metrics.cost_micros) for r in yesterday_results)
    week_conv = sum(r.metrics.conversions for r in week)
    week_cost = sum(micros_to_currency(r.metrics.cost_micros) for r in week)
    
    daily_avg_conv = week_conv / 7 if week_conv > 0 else 0
    
    # Alert if yesterday had significant spend but way fewer conversions than average
    if yesterday_cost > 50 and daily_avg_conv > 1:
        if yesterday_conv < daily_avg_conv * 0.3:  # Less than 30% of average
            issues.append(Issue(
                type="CONVERSION_DROP",
                severity=Severity.HIGH,
                account=account['name'],
                message=f"Yesterday: {yesterday_conv:.0f} conversions vs {daily_avg_conv:.1f} daily avg ({format_currency(yesterday_cost)} spent)",
                details={
                    "yesterday_conversions": yesterday_conv,
                    "daily_average": daily_avg_conv,
                    "yesterday_cost": yesterday_cost,
                    "drop_percent": (1 - yesterday_conv / daily_avg_conv) * 100 if daily_avg_conv > 0 else 0,
                }
            ))
        elif yesterday_conv == 0 and yesterday_cost > 100:
            issues.append(Issue(
                type="NO_CONVERSIONS",
                severity=Severity.CRITICAL,
                account=account['name'],
                message=f"Zero conversions yesterday with {format_currency(yesterday_cost)} spend! Check tracking.",
                details={
                    "yesterday_cost": yesterday_cost,
                    "daily_average": daily_avg_conv,
                }
            ))
    
    return issues


def check_budget_pacing(client, account_key: str) -> List[Issue]:
    """Check if campaigns are pacing correctly against budget."""
    account = ACCOUNTS[account_key]
    thresholds = get_thresholds()
    issues = []
    yesterday = yesterday_date()
    
    query = f"""
        SELECT
            campaign.name,
            campaign.campaign_budget,
            campaign_budget.amount_micros,
            metrics.cost_micros
        FROM campaign
        WHERE segments.date = '{yesterday}'
          AND campaign.status = 'ENABLED'
    """
    
    results = run_query(client, account['id'], query)
    
    for row in results:
        if not row.campaign_budget.amount_micros:
            continue
            
        daily_budget = micros_to_currency(row.campaign_budget.amount_micros)
        yesterday_spend = micros_to_currency(row.metrics.cost_micros)
        
        if daily_budget > 0:
            pacing = yesterday_spend / daily_budget
            
            if pacing < thresholds['budget_pacing_min']:
                issues.append(Issue(
                    type="UNDERSPENDING",
                    severity=Severity.MEDIUM,
                    account=account['name'],
                    message=f"'{row.campaign.name}' spent only {pacing:.0%} of budget ({format_currency(yesterday_spend)}/{format_currency(daily_budget)})",
                    details={
                        "campaign": row.campaign.name,
                        "daily_budget": daily_budget,
                        "yesterday_spend": yesterday_spend,
                        "pacing": pacing,
                    }
                ))
            elif pacing > thresholds['budget_pacing_max'] * 1.5:  # Significant overspend
                issues.append(Issue(
                    type="OVERSPENDING",
                    severity=Severity.MEDIUM,
                    account=account['name'],
                    message=f"'{row.campaign.name}' overspent: {format_currency(yesterday_spend)} vs {format_currency(daily_budget)} budget",
                    details={
                        "campaign": row.campaign.name,
                        "daily_budget": daily_budget,
                        "yesterday_spend": yesterday_spend,
                        "overspend": yesterday_spend - daily_budget,
                    }
                ))
    
    return issues


def check_cpa_anomalies(client, account_key: str) -> List[Issue]:
    """Check for CPA anomalies vs historical average."""
    account = ACCOUNTS[account_key]
    thresholds = get_thresholds()
    issues = []
    yesterday = yesterday_date()
    
    # Yesterday's performance
    query_yesterday = f"""
        SELECT
            campaign.name,
            metrics.cost_micros,
            metrics.conversions
        FROM campaign
        WHERE segments.date = '{yesterday}'
          AND campaign.status = 'ENABLED'
          AND metrics.cost_micros > 0
    """
    
    # 30-day average
    query_month = """
        SELECT
            campaign.name,
            metrics.cost_micros,
            metrics.conversions
        FROM campaign
        WHERE segments.date DURING LAST_30_DAYS
          AND campaign.status = 'ENABLED'
    """
    
    yesterday_results = run_query(client, account['id'], query_yesterday)
    month = run_query(client, account['id'], query_month)
    
    # Calculate account-level average CPA
    total_cost_month = sum(micros_to_currency(r.metrics.cost_micros) for r in month)
    total_conv_month = sum(r.metrics.conversions for r in month)
    avg_cpa = total_cost_month / total_conv_month if total_conv_month > 0 else 0
    
    for row in yesterday_results:
        cost = micros_to_currency(row.metrics.cost_micros)
        conv = row.metrics.conversions
        
        if conv > 0 and cost > 50:  # Meaningful spend
            campaign_cpa = cost / conv
            if campaign_cpa > avg_cpa * thresholds['high_cpa_multiplier']:
                issues.append(Issue(
                    type="HIGH_CPA",
                    severity=Severity.MEDIUM,
                    account=account['name'],
                    message=f"'{row.campaign.name}' CPA yesterday: {format_currency(campaign_cpa)} ({campaign_cpa/avg_cpa:.1f}x avg of {format_currency(avg_cpa)})",
                    details={
                        "campaign": row.campaign.name,
                        "yesterday_cpa": campaign_cpa,
                        "avg_cpa": avg_cpa,
                        "multiplier": campaign_cpa / avg_cpa,
                    }
                ))
    
    return issues


def check_quality_scores(client, account_key: str) -> List[Issue]:
    """Check for low quality score keywords."""
    account = ACCOUNTS[account_key]
    thresholds = get_thresholds()
    issues = []
    
    query = """
        SELECT
            ad_group_criterion.keyword.text,
            ad_group_criterion.quality_info.quality_score,
            campaign.name,
            metrics.cost_micros,
            metrics.impressions
        FROM keyword_view
        WHERE ad_group_criterion.status = 'ENABLED'
          AND campaign.status = 'ENABLED'
          AND ad_group_criterion.quality_info.quality_score IS NOT NULL
          AND metrics.impressions > 100
        ORDER BY ad_group_criterion.quality_info.quality_score ASC
        LIMIT 20
    """
    
    results = run_query(client, account['id'], query)
    
    low_qs_keywords = []
    for row in results:
        qs = row.ad_group_criterion.quality_info.quality_score
        cost = micros_to_currency(row.metrics.cost_micros)
        
        if qs is not None and qs < thresholds['quality_score_min'] and cost > 10:
            low_qs_keywords.append({
                'keyword': row.ad_group_criterion.keyword.text,
                'qs': qs,
                'campaign': row.campaign.name,
                'cost': cost,
            })
    
    if low_qs_keywords:
        total_cost = sum(k['cost'] for k in low_qs_keywords)
        issues.append(Issue(
            type="LOW_QUALITY_SCORE",
            severity=Severity.LOW,
            account=account['name'],
            message=f"{len(low_qs_keywords)} keywords with QS < {thresholds['quality_score_min']} (combined {format_currency(total_cost)} spend)",
            details={
                "keywords": low_qs_keywords[:5],
                "total_count": len(low_qs_keywords),
                "total_cost": total_cost,
            }
        ))
    
    return issues


def check_disapproved_ads(client, account_key: str) -> List[Issue]:
    """Check for disapproved ads."""
    account = ACCOUNTS[account_key]
    issues = []
    
    query = """
        SELECT
            ad_group_ad.ad.id,
            ad_group_ad.policy_summary.approval_status,
            ad_group_ad.policy_summary.policy_topic_entries,
            campaign.name,
            ad_group.name
        FROM ad_group_ad
        WHERE ad_group_ad.policy_summary.approval_status IN ('DISAPPROVED', 'AREA_OF_INTEREST_ONLY')
          AND campaign.status = 'ENABLED'
    """
    
    results = run_query(client, account['id'], query)
    
    if results:
        issues.append(Issue(
            type="DISAPPROVED_ADS",
            severity=Severity.HIGH,
            account=account['name'],
            message=f"{len(results)} disapproved ad(s) - your ads aren't showing!",
            details={
                "count": len(results),
                "campaigns": list(set(r.campaign.name for r in results))[:5],
            }
        ))
    
    return issues


def get_yesterday_summary(client, account_key: str) -> dict:
    """Get yesterday's performance summary."""
    account = ACCOUNTS[account_key]
    yesterday = yesterday_date()
    
    query = f"""
        SELECT
            metrics.cost_micros,
            metrics.conversions,
            metrics.clicks,
            metrics.impressions,
            metrics.conversions_value
        FROM customer
        WHERE segments.date = '{yesterday}'
    """
    
    results = run_query(client, account['id'], query)
    
    if not results:
        return None
    
    row = results[0]
    cost = micros_to_currency(row.metrics.cost_micros)
    conv = row.metrics.conversions
    
    return {
        'cost': cost,
        'conversions': conv,
        'clicks': row.metrics.clicks,
        'impressions': row.metrics.impressions,
        'cpa': cost / conv if conv > 0 else 0,
        'conversion_value': micros_to_currency(row.metrics.conversions_value * 1_000_000) if hasattr(row.metrics, 'conversions_value') else 0,
        'roas': row.metrics.conversions_value / cost if cost > 0 and hasattr(row.metrics, 'conversions_value') else 0,
    }


def run_daily_health_check() -> Tuple[List[Issue], dict]:
    """Run all daily health checks."""
    client = get_client()
    all_issues = []
    summaries = {}
    
    checks = [
        ("Conversion Tracking", check_conversion_tracking),
        ("Budget Pacing", check_budget_pacing),
        ("CPA Anomalies", check_cpa_anomalies),
        ("Quality Scores", check_quality_scores),
        ("Disapproved Ads", check_disapproved_ads),
    ]
    
    for account_key in ACCOUNTS:
        account = ACCOUNTS[account_key]
        print(f"Checking {account['name']}...", file=sys.stderr)
        
        # Get summary
        summary = get_yesterday_summary(client, account_key)
        if summary:
            summaries[account_key] = summary
        
        # Run checks
        for check_name, check_fn in checks:
            try:
                issues = check_fn(client, account_key)
                all_issues.extend(issues)
            except Exception as e:
                print(f"  {check_name} error: {e}", file=sys.stderr)
    
    return all_issues, summaries


def format_daily_report(issues: List[Issue], summaries: dict) -> str:
    """Format daily report for Telegram."""
    report = f"📊 **Google Ads Daily Report**\n"
    report += f"_{datetime.now().strftime('%A, %B %d, %Y')}_\n\n"
    
    # Yesterday's summary
    report += "**Yesterday's Performance**\n"
    
    total_cost = 0
    total_conv = 0
    
    for account_key, summary in summaries.items():
        account = ACCOUNTS[account_key]
        total_cost += summary['cost']
        total_conv += summary['conversions']
        
        cpa_str = format_currency(summary['cpa']) if summary['cpa'] > 0 else "N/A"
        report += f"• {account['name']}: {format_currency(summary['cost'])} | {summary['conversions']:.0f} conv | CPA: {cpa_str}\n"
    
    total_cpa = total_cost / total_conv if total_conv > 0 else 0
    report += f"\n**Total:** {format_currency(total_cost)} | {total_conv:.0f} conv | CPA: {format_currency(total_cpa)}\n\n"
    
    # Issues
    if not issues:
        report += "✅ **No Issues Detected**\nAll accounts look healthy!\n"
    else:
        # Group by severity
        critical = [i for i in issues if i.severity in [Severity.CRITICAL, Severity.HIGH]]
        medium = [i for i in issues if i.severity == Severity.MEDIUM]
        low = [i for i in issues if i.severity == Severity.LOW]
        
        if critical:
            report += "🚨 **Critical/High Priority**\n"
            for issue in critical:
                report += f"• {issue.message}\n"
            report += "\n"
        
        if medium:
            report += "⚠️ **Medium Priority**\n"
            for issue in medium[:5]:
                report += f"• {issue.message}\n"
            if len(medium) > 5:
                report += f"_...and {len(medium) - 5} more_\n"
            report += "\n"
        
        if low:
            report += f"📝 **{len(low)} Low Priority Items**\n"
    
    return report


def main():
    parser = argparse.ArgumentParser(description="Daily Google Ads health check")
    parser.add_argument("--json", action="store_true", help="Output as JSON")
    parser.add_argument("--quiet", action="store_true", help="Only output if issues found")
    args = parser.parse_args()
    
    issues, summaries = run_daily_health_check()
    
    if args.quiet and not issues:
        return
    
    if args.json:
        import json
        output = {
            "issues": [i.to_dict() for i in issues],
            "summaries": summaries,
            "timestamp": datetime.now().isoformat(),
        }
        print(json.dumps(output, indent=2))
    else:
        print(format_daily_report(issues, summaries))


if __name__ == "__main__":
    main()
