// ============================================
// PERFORMANCE & REPORTING TOOLS
// ============================================

import type { ToolDefinition, ToolResult, GoogleAdsClient } from "../types.js";
import { microsToMoney, formatPercent, formatNumber } from "../types.js";

function text(t: string): ToolResult {
  return { content: [{ type: "text", text: t }] };
}

function errorResult(msg: string): ToolResult {
  return { content: [{ type: "text", text: `❌ ${msg}` }], isError: true };
}

const DATE_RANGE_ENUM = [
  "TODAY", "YESTERDAY", "LAST_7_DAYS", "LAST_30_DAYS",
  "THIS_MONTH", "LAST_MONTH", "THIS_QUARTER", "LAST_QUARTER",
];

/** Compute derived metrics from raw values */
function derivedMetrics(m: any) {
  const impressions = Number(m.impressions || 0);
  const clicks = Number(m.clicks || 0);
  const costMicros = Number(m.costMicros || 0);
  const conversions = Number(m.conversions || 0);

  const cost = costMicros / 1_000_000;
  const ctr = impressions > 0 ? clicks / impressions : 0;
  const avgCpc = clicks > 0 ? cost / clicks : 0;
  const convRate = clicks > 0 ? conversions / clicks : 0;
  const costPerConv = conversions > 0 ? cost / conversions : 0;

  return { impressions, clicks, cost, costMicros, conversions, ctr, avgCpc, convRate, costPerConv };
}

// ─── get_performance_summary ────────────────────────────────────────
const getPerformanceSummary: ToolDefinition = {
  name: "get_performance_summary",
  description:
    "Get account-level performance KPIs: impressions, clicks, cost, conversions, CTR, " +
    "average CPC, and conversion rate. Provides a high-level overview of account health.",
  category: "reporting",
  annotations: {
    title: "Get Performance Summary",
    readOnlyHint: true,
    destructiveHint: false,
    idempotentHint: true,
    openWorldHint: false,
  },
  inputSchema: {
    type: "object",
    properties: {
      customer_id: {
        type: "string",
        description: "Google Ads customer ID. Uses default if not provided.",
      },
      date_range: {
        type: "string",
        description: "Date range for metrics.",
        enum: DATE_RANGE_ENUM,
        default: "LAST_30_DAYS",
      },
    },
  },
  _meta: {
    labels: {
      category: "reporting",
      access: "read",
      complexity: "simple"
    }
  },
  handler: async (args: Record<string, any>, client: GoogleAdsClient): Promise<ToolResult> => {
    const customerId = args.customer_id || client.getCustomerId();
    if (!customerId) return errorResult("No customer ID provided and no default configured.");

    const dateRange = args.date_range || "LAST_30_DAYS";

    const query = `
      SELECT
        metrics.impressions,
        metrics.clicks,
        metrics.cost_micros,
        metrics.conversions,
        metrics.conversions_value,
        metrics.ctr,
        metrics.average_cpc,
        metrics.all_conversions,
        metrics.interactions
      FROM customer
      WHERE segments.date DURING ${dateRange}
    `;

    const results = await client.query(customerId, query);
    if (!results.length) return text(`No performance data available for ${dateRange}.`);

    const m = results[0].metrics || {};
    const d = derivedMetrics(m);

    return text(
      `## 📊 Account Performance Summary\n\n` +
      `**Account:** \`${customerId}\` · **Period:** ${dateRange}\n\n` +
      `| KPI | Value |\n` +
      `|-----|-------|\n` +
      `| **Impressions** | ${formatNumber(d.impressions)} |\n` +
      `| **Clicks** | ${formatNumber(d.clicks)} |\n` +
      `| **CTR** | ${formatPercent(d.ctr)} |\n` +
      `| **Cost** | $${d.cost.toFixed(2)} |\n` +
      `| **Avg. CPC** | $${d.avgCpc.toFixed(2)} |\n` +
      `| **Conversions** | ${d.conversions.toFixed(1)} |\n` +
      `| **Conv. Rate** | ${formatPercent(d.convRate)} |\n` +
      `| **Cost / Conv.** | $${d.costPerConv.toFixed(2)} |\n` +
      `| **Conv. Value** | $${Number(m.conversionsValue || 0).toFixed(2)} |\n` +
      `| **All Conversions** | ${Number(m.allConversions || 0).toFixed(1)} |\n` +
      `| **Interactions** | ${formatNumber(m.interactions || 0)} |`
    );
  },
};

// ─── get_campaign_performance ───────────────────────────────────────
const getCampaignPerformance: ToolDefinition = {
  name: "get_campaign_performance",
  description:
    "Get campaign-level performance metrics. Can report on all campaigns or a specific one. " +
    "Includes impressions, clicks, cost, conversions, CTR, CPC, and conversion rate.",
  category: "reporting",
  annotations: {
    title: "Get Campaign Performance",
    readOnlyHint: true,
    destructiveHint: false,
    idempotentHint: true,
    openWorldHint: false,
  },
  inputSchema: {
    type: "object",
    properties: {
      customer_id: {
        type: "string",
        description: "Google Ads customer ID. Uses default if not provided.",
      },
      campaign_id: {
        type: "string",
        description: "Specific campaign ID to report on. Omit for all campaigns.",
      },
      date_range: {
        type: "string",
        description: "Date range for metrics.",
        enum: DATE_RANGE_ENUM,
        default: "LAST_30_DAYS",
      },
      limit: {
        type: "number",
        description: "Max campaigns to return (default 25).",
        default: 25,
      },
      order_by: {
        type: "string",
        description: "Metric to sort by (descending).",
        enum: ["cost", "clicks", "impressions", "conversions", "ctr"],
        default: "cost",
      },
    },
  },
  _meta: {
    labels: {
      category: "reporting",
      access: "read",
      complexity: "simple"
    }
  },
  handler: async (args: Record<string, any>, client: GoogleAdsClient): Promise<ToolResult> => {
    const customerId = args.customer_id || client.getCustomerId();
    if (!customerId) return errorResult("No customer ID provided and no default configured.");

    const dateRange = args.date_range || "LAST_30_DAYS";
    const limit = args.limit || 25;

    const orderMap: Record<string, string> = {
      cost: "metrics.cost_micros",
      clicks: "metrics.clicks",
      impressions: "metrics.impressions",
      conversions: "metrics.conversions",
      ctr: "metrics.ctr",
    };
    const orderBy = orderMap[args.order_by || "cost"] || "metrics.cost_micros";

    const conditions = [`segments.date DURING ${dateRange}`];
    if (args.campaign_id) {
      conditions.push(`campaign.id = ${args.campaign_id}`);
    }
    conditions.push(`campaign.status != 'REMOVED'`);

    const query = `
      SELECT
        campaign.id,
        campaign.name,
        campaign.status,
        campaign.advertising_channel_type,
        metrics.impressions,
        metrics.clicks,
        metrics.cost_micros,
        metrics.conversions,
        metrics.conversions_value,
        metrics.ctr,
        metrics.average_cpc
      FROM campaign
      WHERE ${conditions.join(" AND ")}
      ORDER BY ${orderBy} DESC
      LIMIT ${limit}
    `;

    const results = await client.query(customerId, query);
    if (!results.length) return text("No campaign performance data available for this period.");

    const header =
      `| Campaign | Status | Type | Impr. | Clicks | CTR | Cost | Avg CPC | Conv. | Conv Rate |\n` +
      `|----------|--------|------|-------|--------|-----|------|---------|-------|-----------| `;

    const rows = results.map((r: any) => {
      const c = r.campaign;
      const m = r.metrics || {};
      const d = derivedMetrics(m);
      return (
        `| ${c.name || "—"} | ${c.status} | ${c.advertisingChannelType || "—"} | ` +
        `${formatNumber(d.impressions)} | ${formatNumber(d.clicks)} | ${formatPercent(d.ctr)} | ` +
        `$${d.cost.toFixed(2)} | $${d.avgCpc.toFixed(2)} | ` +
        `${d.conversions.toFixed(1)} | ${formatPercent(d.convRate)} |`
      );
    });

    // Totals row
    const totals = results.reduce(
      (acc: any, r: any) => {
        const m = r.metrics || {};
        acc.impressions += Number(m.impressions || 0);
        acc.clicks += Number(m.clicks || 0);
        acc.costMicros += Number(m.costMicros || 0);
        acc.conversions += Number(m.conversions || 0);
        return acc;
      },
      { impressions: 0, clicks: 0, costMicros: 0, conversions: 0 }
    );
    const tCost = totals.costMicros / 1_000_000;
    const tCtr = totals.impressions > 0 ? totals.clicks / totals.impressions : 0;
    const tCpc = totals.clicks > 0 ? tCost / totals.clicks : 0;
    const tConvRate = totals.clicks > 0 ? totals.conversions / totals.clicks : 0;

    const totalsRow =
      `| **TOTAL** | — | — | ${formatNumber(totals.impressions)} | ${formatNumber(totals.clicks)} | ` +
      `${formatPercent(tCtr)} | $${tCost.toFixed(2)} | $${tCpc.toFixed(2)} | ` +
      `${totals.conversions.toFixed(1)} | ${formatPercent(tConvRate)} |`;

    return text(
      `## 📈 Campaign Performance\n\n` +
      `**Account:** \`${customerId}\` · **Period:** ${dateRange} · **Sorted by:** ${args.order_by || "cost"}\n\n` +
      `${header}\n${rows.join("\n")}\n${totalsRow}`
    );
  },
};

// ─── get_ad_group_performance ───────────────────────────────────────
const getAdGroupPerformance: ToolDefinition = {
  name: "get_ad_group_performance",
  description:
    "Get ad group-level performance metrics. Optionally filter by campaign ID. " +
    "Shows impressions, clicks, cost, conversions, CTR, and CPC per ad group.",
  category: "reporting",
  annotations: {
    title: "Get Ad Group Performance",
    readOnlyHint: true,
    destructiveHint: false,
    idempotentHint: true,
    openWorldHint: false,
  },
  inputSchema: {
    type: "object",
    properties: {
      customer_id: {
        type: "string",
        description: "Google Ads customer ID. Uses default if not provided.",
      },
      campaign_id: {
        type: "string",
        description: "Filter by campaign ID. Omit for all campaigns.",
      },
      date_range: {
        type: "string",
        description: "Date range for metrics.",
        enum: DATE_RANGE_ENUM,
        default: "LAST_30_DAYS",
      },
      limit: {
        type: "number",
        description: "Max ad groups to return (default 50).",
        default: 50,
      },
    },
  },
  _meta: {
    labels: {
      category: "reporting",
      access: "read",
      complexity: "simple"
    }
  },
  handler: async (args: Record<string, any>, client: GoogleAdsClient): Promise<ToolResult> => {
    const customerId = args.customer_id || client.getCustomerId();
    if (!customerId) return errorResult("No customer ID provided and no default configured.");

    const dateRange = args.date_range || "LAST_30_DAYS";
    const limit = args.limit || 50;

    const conditions = [
      `segments.date DURING ${dateRange}`,
      `ad_group.status != 'REMOVED'`,
    ];
    if (args.campaign_id) {
      conditions.push(`campaign.id = ${args.campaign_id}`);
    }

    const query = `
      SELECT
        ad_group.id,
        ad_group.name,
        ad_group.status,
        ad_group.type,
        campaign.id,
        campaign.name,
        metrics.impressions,
        metrics.clicks,
        metrics.cost_micros,
        metrics.conversions,
        metrics.ctr,
        metrics.average_cpc
      FROM ad_group
      WHERE ${conditions.join(" AND ")}
      ORDER BY metrics.cost_micros DESC
      LIMIT ${limit}
    `;

    const results = await client.query(customerId, query);
    if (!results.length) return text("No ad group performance data available for this period.");

    const header =
      `| Ad Group | Campaign | Status | Type | Impr. | Clicks | CTR | Cost | CPC | Conv. |\n` +
      `|----------|----------|--------|------|-------|--------|-----|------|-----|-------|`;

    const rows = results.map((r: any) => {
      const ag = r.adGroup;
      const c = r.campaign;
      const m = r.metrics || {};
      const d = derivedMetrics(m);
      return (
        `| ${ag.name || "—"} | ${c.name || "—"} | ${ag.status} | ${ag.type || "—"} | ` +
        `${formatNumber(d.impressions)} | ${formatNumber(d.clicks)} | ${formatPercent(d.ctr)} | ` +
        `$${d.cost.toFixed(2)} | $${d.avgCpc.toFixed(2)} | ${d.conversions.toFixed(1)} |`
      );
    });

    return text(
      `## 📊 Ad Group Performance\n\n` +
      `**Account:** \`${customerId}\` · **Period:** ${dateRange}` +
      `${args.campaign_id ? ` · **Campaign:** \`${args.campaign_id}\`` : ""}\n\n` +
      `${header}\n${rows.join("\n")}\n\n` +
      `Showing ${results.length} ad group(s), sorted by cost (descending).`
    );
  },
};

// ─── get_keyword_performance ────────────────────────────────────────
const getKeywordPerformance: ToolDefinition = {
  name: "get_keyword_performance",
  description:
    "Get keyword-level performance metrics with quality scores. Shows keyword text, match type, " +
    "quality score components, impressions, clicks, cost, and conversions.",
  category: "reporting",
  annotations: {
    title: "Get Keyword Performance",
    readOnlyHint: true,
    destructiveHint: false,
    idempotentHint: true,
    openWorldHint: false,
  },
  inputSchema: {
    type: "object",
    properties: {
      customer_id: {
        type: "string",
        description: "Google Ads customer ID. Uses default if not provided.",
      },
      campaign_id: {
        type: "string",
        description: "Filter by campaign ID.",
      },
      ad_group_id: {
        type: "string",
        description: "Filter by ad group ID.",
      },
      date_range: {
        type: "string",
        description: "Date range for metrics.",
        enum: DATE_RANGE_ENUM,
        default: "LAST_30_DAYS",
      },
      limit: {
        type: "number",
        description: "Max keywords to return (default 50).",
        default: 50,
      },
    },
  },
  _meta: {
    labels: {
      category: "reporting",
      access: "read",
      complexity: "simple"
    }
  },
  handler: async (args: Record<string, any>, client: GoogleAdsClient): Promise<ToolResult> => {
    const customerId = args.customer_id || client.getCustomerId();
    if (!customerId) return errorResult("No customer ID provided and no default configured.");

    const dateRange = args.date_range || "LAST_30_DAYS";
    const limit = args.limit || 50;

    const conditions = [
      `segments.date DURING ${dateRange}`,
      `ad_group_criterion.status != 'REMOVED'`,
      `ad_group_criterion.type = 'KEYWORD'`,
    ];
    if (args.campaign_id) conditions.push(`campaign.id = ${args.campaign_id}`);
    if (args.ad_group_id) conditions.push(`ad_group.id = ${args.ad_group_id}`);

    const query = `
      SELECT
        ad_group_criterion.criterion_id,
        ad_group_criterion.keyword.text,
        ad_group_criterion.keyword.match_type,
        ad_group_criterion.status,
        ad_group_criterion.quality_info.quality_score,
        ad_group_criterion.quality_info.creative_quality_score,
        ad_group_criterion.quality_info.search_predicted_ctr,
        ad_group_criterion.quality_info.post_click_quality_score,
        ad_group.name,
        campaign.name,
        metrics.impressions,
        metrics.clicks,
        metrics.cost_micros,
        metrics.conversions,
        metrics.ctr,
        metrics.average_cpc
      FROM keyword_view
      WHERE ${conditions.join(" AND ")}
      ORDER BY metrics.cost_micros DESC
      LIMIT ${limit}
    `;

    const results = await client.query(customerId, query);
    if (!results.length) return text("No keyword performance data available for this period.");

    const header =
      `| Keyword | Match | QS | Status | Impr. | Clicks | CTR | Cost | CPC | Conv. |\n` +
      `|---------|-------|----|--------|-------|--------|-----|------|-----|-------|`;

    const rows = results.map((r: any) => {
      const kw = r.adGroupCriterion;
      const m = r.metrics || {};
      const d = derivedMetrics(m);
      const qs = kw.qualityInfo?.qualityScore ?? "—";
      return (
        `| ${kw.keyword?.text || "—"} | ${kw.keyword?.matchType || "—"} | ${qs} | ${kw.status} | ` +
        `${formatNumber(d.impressions)} | ${formatNumber(d.clicks)} | ${formatPercent(d.ctr)} | ` +
        `$${d.cost.toFixed(2)} | $${d.avgCpc.toFixed(2)} | ${d.conversions.toFixed(1)} |`
      );
    });

    // Quality score breakdown for top keywords
    const qsDetails = results
      .filter((r: any) => r.adGroupCriterion.qualityInfo?.qualityScore != null)
      .slice(0, 10)
      .map((r: any) => {
        const kw = r.adGroupCriterion;
        const qi = kw.qualityInfo || {};
        return (
          `| ${kw.keyword?.text || "—"} | ${qi.qualityScore ?? "—"} | ` +
          `${qi.searchPredictedCtr || "—"} | ${qi.creativeQualityScore || "—"} | ` +
          `${qi.postClickQualityScore || "—"} |`
        );
      });

    let qsSection = "";
    if (qsDetails.length) {
      qsSection =
        `\n\n### Quality Score Breakdown (Top 10)\n\n` +
        `| Keyword | QS | Expected CTR | Ad Relevance | Landing Page |\n` +
        `|---------|----|--------------|--------------|--------------|\n` +
        qsDetails.join("\n");
    }

    return text(
      `## 🔑 Keyword Performance\n\n` +
      `**Account:** \`${customerId}\` · **Period:** ${dateRange}\n\n` +
      `${header}\n${rows.join("\n")}${qsSection}\n\n` +
      `Showing ${results.length} keyword(s), sorted by cost (descending).`
    );
  },
};

// ─── get_search_terms_report ────────────────────────────────────────
const getSearchTermsReport: ToolDefinition = {
  name: "get_search_terms_report",
  description:
    "Get the actual search terms that triggered your ads. Shows what users typed to trigger " +
    "your ads, which keywords matched, and performance for each search term. Useful for " +
    "discovering new keywords and finding negatives.",
  category: "reporting",
  annotations: {
    title: "Get Search Terms Report",
    readOnlyHint: true,
    destructiveHint: false,
    idempotentHint: true,
    openWorldHint: true,
  },
  inputSchema: {
    type: "object",
    properties: {
      customer_id: {
        type: "string",
        description: "Google Ads customer ID. Uses default if not provided.",
      },
      campaign_id: {
        type: "string",
        description: "Filter by campaign ID.",
      },
      ad_group_id: {
        type: "string",
        description: "Filter by ad group ID.",
      },
      date_range: {
        type: "string",
        description: "Date range for report.",
        enum: DATE_RANGE_ENUM,
        default: "LAST_30_DAYS",
      },
      limit: {
        type: "number",
        description: "Max search terms to return (default 50).",
        default: 50,
      },
    },
  },
  _meta: {
    labels: {
      category: "reporting",
      access: "read",
      complexity: "complex"
    }
  },
  handler: async (args: Record<string, any>, client: GoogleAdsClient): Promise<ToolResult> => {
    const customerId = args.customer_id || client.getCustomerId();
    if (!customerId) return errorResult("No customer ID provided and no default configured.");

    const dateRange = args.date_range || "LAST_30_DAYS";
    const limit = args.limit || 50;

    const conditions = [`segments.date DURING ${dateRange}`];
    if (args.campaign_id) conditions.push(`campaign.id = ${args.campaign_id}`);
    if (args.ad_group_id) conditions.push(`ad_group.id = ${args.ad_group_id}`);

    const query = `
      SELECT
        search_term_view.search_term,
        search_term_view.status,
        campaign.id,
        campaign.name,
        ad_group.id,
        ad_group.name,
        metrics.impressions,
        metrics.clicks,
        metrics.cost_micros,
        metrics.conversions,
        metrics.ctr
      FROM search_term_view
      WHERE ${conditions.join(" AND ")}
      ORDER BY metrics.impressions DESC
      LIMIT ${limit}
    `;

    const results = await client.query(customerId, query);
    if (!results.length) return text("No search term data available for this period.");

    const header =
      `| Search Term | Campaign | Ad Group | Status | Impr. | Clicks | CTR | Cost | Conv. |\n` +
      `|-------------|----------|----------|--------|-------|--------|-----|------|-------|`;

    const rows = results.map((r: any) => {
      const st = r.searchTermView;
      const c = r.campaign;
      const ag = r.adGroup;
      const m = r.metrics || {};
      const d = derivedMetrics(m);
      return (
        `| ${st.searchTerm || "—"} | ${c.name || "—"} | ${ag.name || "—"} | ` +
        `${st.status || "—"} | ${formatNumber(d.impressions)} | ${formatNumber(d.clicks)} | ` +
        `${formatPercent(d.ctr)} | $${d.cost.toFixed(2)} | ${d.conversions.toFixed(1)} |`
      );
    });

    // Summary stats
    const totals = results.reduce(
      (acc: any, r: any) => {
        const m = r.metrics || {};
        acc.impressions += Number(m.impressions || 0);
        acc.clicks += Number(m.clicks || 0);
        acc.cost += Number(m.costMicros || 0) / 1_000_000;
        acc.conversions += Number(m.conversions || 0);
        return acc;
      },
      { impressions: 0, clicks: 0, cost: 0, conversions: 0 }
    );

    return text(
      `## 🔍 Search Terms Report\n\n` +
      `**Account:** \`${customerId}\` · **Period:** ${dateRange}\n\n` +
      `**Summary:** ${formatNumber(totals.impressions)} impressions, ${formatNumber(totals.clicks)} clicks, ` +
      `$${totals.cost.toFixed(2)} cost, ${totals.conversions.toFixed(1)} conversions across ${results.length} search terms\n\n` +
      `${header}\n${rows.join("\n")}\n\n` +
      `💡 **Tip:** Look for high-impression, low-conversion terms to add as negative keywords. ` +
      `High-converting terms can be added as exact-match keywords.`
    );
  },
};

// ─── get_geo_performance ────────────────────────────────────────────
const getGeoPerformance: ToolDefinition = {
  name: "get_geo_performance",
  description:
    "Get performance metrics broken down by geographic location. Shows which countries, " +
    "regions, or cities are driving traffic and conversions.",
  category: "reporting",
  annotations: {
    title: "Get Geographic Performance",
    readOnlyHint: true,
    destructiveHint: false,
    idempotentHint: true,
    openWorldHint: false,
  },
  inputSchema: {
    type: "object",
    properties: {
      customer_id: {
        type: "string",
        description: "Google Ads customer ID. Uses default if not provided.",
      },
      campaign_id: {
        type: "string",
        description: "Filter by campaign ID.",
      },
      date_range: {
        type: "string",
        description: "Date range for metrics.",
        enum: DATE_RANGE_ENUM,
        default: "LAST_30_DAYS",
      },
      limit: {
        type: "number",
        description: "Max locations to return (default 30).",
        default: 30,
      },
    },
  },
  _meta: {
    labels: {
      category: "reporting",
      access: "read",
      complexity: "simple"
    }
  },
  handler: async (args: Record<string, any>, client: GoogleAdsClient): Promise<ToolResult> => {
    const customerId = args.customer_id || client.getCustomerId();
    if (!customerId) return errorResult("No customer ID provided and no default configured.");

    const dateRange = args.date_range || "LAST_30_DAYS";
    const limit = args.limit || 30;

    const conditions = [`segments.date DURING ${dateRange}`];
    if (args.campaign_id) conditions.push(`campaign.id = ${args.campaign_id}`);

    const query = `
      SELECT
        geographic_view.country_criterion_id,
        geographic_view.location_type,
        campaign.name,
        segments.geo_target_country,
        segments.geo_target_region,
        segments.geo_target_city,
        metrics.impressions,
        metrics.clicks,
        metrics.cost_micros,
        metrics.conversions,
        metrics.ctr,
        metrics.average_cpc
      FROM geographic_view
      WHERE ${conditions.join(" AND ")}
      ORDER BY metrics.cost_micros DESC
      LIMIT ${limit}
    `;

    const results = await client.query(customerId, query);
    if (!results.length) return text("No geographic performance data available for this period.");

    const header =
      `| Location | Type | Campaign | Impr. | Clicks | CTR | Cost | CPC | Conv. | Conv Rate |\n` +
      `|----------|------|----------|-------|--------|-----|------|-----|-------|-----------|`;

    const rows = results.map((r: any) => {
      const geo = r.geographicView;
      const seg = r.segments || {};
      const c = r.campaign;
      const m = r.metrics || {};
      const d = derivedMetrics(m);

      // Build location name from available segments
      const locationParts = [
        seg.geoTargetCity,
        seg.geoTargetRegion,
        seg.geoTargetCountry,
      ].filter(Boolean);
      const location = locationParts.length > 0 ? locationParts.join(", ") : `ID: ${geo.countryCriterionId || "—"}`;

      return (
        `| ${location} | ${geo.locationType || "—"} | ${c.name || "—"} | ` +
        `${formatNumber(d.impressions)} | ${formatNumber(d.clicks)} | ${formatPercent(d.ctr)} | ` +
        `$${d.cost.toFixed(2)} | $${d.avgCpc.toFixed(2)} | ` +
        `${d.conversions.toFixed(1)} | ${formatPercent(d.convRate)} |`
      );
    });

    return text(
      `## 🌍 Geographic Performance\n\n` +
      `**Account:** \`${customerId}\` · **Period:** ${dateRange}\n\n` +
      `${header}\n${rows.join("\n")}\n\n` +
      `Showing top ${results.length} location(s) by cost.`
    );
  },
};

// ─── get_device_performance ─────────────────────────────────────────
const getDevicePerformance: ToolDefinition = {
  name: "get_device_performance",
  description:
    "Get performance metrics broken down by device type (desktop, mobile, tablet). " +
    "Helps identify which devices drive the best results for bid adjustments.",
  category: "reporting",
  annotations: {
    title: "Get Device Performance",
    readOnlyHint: true,
    destructiveHint: false,
    idempotentHint: true,
    openWorldHint: false,
  },
  inputSchema: {
    type: "object",
    properties: {
      customer_id: {
        type: "string",
        description: "Google Ads customer ID. Uses default if not provided.",
      },
      campaign_id: {
        type: "string",
        description: "Filter by campaign ID.",
      },
      date_range: {
        type: "string",
        description: "Date range for metrics.",
        enum: DATE_RANGE_ENUM,
        default: "LAST_30_DAYS",
      },
    },
  },
  _meta: {
    labels: {
      category: "reporting",
      access: "read",
      complexity: "simple"
    }
  },
  handler: async (args: Record<string, any>, client: GoogleAdsClient): Promise<ToolResult> => {
    const customerId = args.customer_id || client.getCustomerId();
    if (!customerId) return errorResult("No customer ID provided and no default configured.");

    const dateRange = args.date_range || "LAST_30_DAYS";

    const conditions = [`segments.date DURING ${dateRange}`];
    if (args.campaign_id) conditions.push(`campaign.id = ${args.campaign_id}`);

    const query = `
      SELECT
        segments.device,
        metrics.impressions,
        metrics.clicks,
        metrics.cost_micros,
        metrics.conversions,
        metrics.conversions_value,
        metrics.ctr,
        metrics.average_cpc
      FROM campaign
      WHERE ${conditions.join(" AND ")}
    `;

    const results = await client.query(customerId, query);
    if (!results.length) return text("No device performance data available for this period.");

    // Aggregate by device type (results may have multiple rows per device across campaigns)
    const byDevice = new Map<string, { impressions: number; clicks: number; costMicros: number; conversions: number; convValue: number }>();

    for (const r of results) {
      const device = r.segments?.device || "UNKNOWN";
      const m = r.metrics || {};
      const existing = byDevice.get(device) || { impressions: 0, clicks: 0, costMicros: 0, conversions: 0, convValue: 0 };
      existing.impressions += Number(m.impressions || 0);
      existing.clicks += Number(m.clicks || 0);
      existing.costMicros += Number(m.costMicros || 0);
      existing.conversions += Number(m.conversions || 0);
      existing.convValue += Number(m.conversionsValue || 0);
      byDevice.set(device, existing);
    }

    // Sort by cost descending
    const sorted = Array.from(byDevice.entries()).sort((a, b) => b[1].costMicros - a[1].costMicros);

    // Total for share calculation
    const totalCost = sorted.reduce((sum, [, v]) => sum + v.costMicros, 0);
    const totalClicks = sorted.reduce((sum, [, v]) => sum + v.clicks, 0);

    const deviceEmoji: Record<string, string> = {
      DESKTOP: "🖥️",
      MOBILE: "📱",
      TABLET: "📱",
      CONNECTED_TV: "📺",
      OTHER: "❓",
      UNKNOWN: "❓",
    };

    const header =
      `| Device | Impr. | Clicks | CTR | Cost | Cost Share | CPC | Conv. | Conv Rate | ROAS |\n` +
      `|--------|-------|--------|-----|------|------------|-----|-------|-----------|------|`;

    const rows = sorted.map(([device, v]) => {
      const cost = v.costMicros / 1_000_000;
      const ctr = v.impressions > 0 ? v.clicks / v.impressions : 0;
      const cpc = v.clicks > 0 ? cost / v.clicks : 0;
      const convRate = v.clicks > 0 ? v.conversions / v.clicks : 0;
      const costShare = totalCost > 0 ? v.costMicros / totalCost : 0;
      const roas = cost > 0 ? v.convValue / cost : 0;
      const emoji = deviceEmoji[device] || "❓";

      return (
        `| ${emoji} ${device} | ${formatNumber(v.impressions)} | ${formatNumber(v.clicks)} | ` +
        `${formatPercent(ctr)} | $${cost.toFixed(2)} | ${formatPercent(costShare)} | ` +
        `$${cpc.toFixed(2)} | ${v.conversions.toFixed(1)} | ${formatPercent(convRate)} | ` +
        `${roas.toFixed(2)}x |`
      );
    });

    return text(
      `## 📱 Device Performance\n\n` +
      `**Account:** \`${customerId}\` · **Period:** ${dateRange}\n\n` +
      `${header}\n${rows.join("\n")}\n\n` +
      `**Total:** ${formatNumber(totalClicks)} clicks · $${(totalCost / 1_000_000).toFixed(2)} cost\n\n` +
      `💡 **Tip:** Use device bid adjustments to increase bids on high-performing devices and reduce spend on low-performing ones.`
    );
  },
};

// ─── Export ─────────────────────────────────────────────────────────
const tools: ToolDefinition[] = [
  getPerformanceSummary,
  getCampaignPerformance,
  getAdGroupPerformance,
  getKeywordPerformance,
  getSearchTermsReport,
  getGeoPerformance,
  getDevicePerformance,
];

export default tools;
