#!/usr/bin/env python3
"""Emit audited EQIX quarterly rows from an offline primary-source manifest."""

from __future__ import annotations

import csv
from pathlib import Path


BASE_DIR = Path(__file__).resolve().parent
MANIFEST = BASE_DIR / "eqix_source_manifest.csv"
OUTPUT = BASE_DIR / "eqix_rows.csv"

FIELDS = [
    "company",
    "period",
    "metric_name",
    "raw_value",
    "normalized_value",
    "unit",
    "value_qualifier",
    "ownership_basis",
    "forecast_or_actual",
    "is_derived",
    "source_url",
    "source_location",
    "source_snippet",
    "snippet_support_status",
    "confidence",
    "caveat",
]

PERIOD_DATA = {
    "2Q24": {
        "capex": ("(648)", "648", "Three Months Ended June 30 2024: Purchases of other property, plant and equipment (648)", "false", "exact"),
        "pipeline": ("54", "54", "projects", "exact", "company_presented", "54 major projects underway in 36 markets", "exact", "high"),
        "revenue": ("2,159", "2.159", "Revenues 2,159 2,127 2,042"),
    },
    "3Q24": {
        "capex": ("(724)", "724", "Three Months Ended September 30 2024: Purchases of other property, plant and equipment (724)", "false", "exact"),
        "pipeline": ("57", "57", "projects", "exact", "company_presented", "57 major projects underway in 35 markets across 22 countries", "exact", "high"),
        "revenue": ("2,201", "2.201", "Revenues 2,201 2,159 2,063"),
    },
    "4Q24": {
        "capex": ("(987)", "987", "Three Months Ended December 31 2024: Purchases of other property, plant and equipment (987)", "false", "exact"),
        "pipeline": ("62", "62", "projects", "exact", "company_presented", "62 major projects underway in 36 markets", "exact", "high"),
        "revenue": ("2,261", "2.261", "Revenues 2,261 2,201 2,127"),
    },
    "1Q25": {
        "capex": ("(750)", "750", "Three Months Ended March 31 2025: Purchases of other property, plant and equipment (750)", "false", "exact"),
        "pipeline": ("56", "56", "projects", "exact", "company_presented", "56 major projects underway in 33 metros across 24 countries", "exact", "high"),
        "revenue": ("2,225", "2.225", "Revenues 2,225 2,261 2,127"),
    },
    "2Q25": {
        "capex": ("989", "989", "Six Months Ended June 30 2025: Purchases of other property, plant and equipment (1,739); less 1Q25 (750) = 2Q25 989", "true", "partial"),
        "capex_location": "Condensed Consolidated Statements of Cash Flows, Six Months Ended; derived quarterly actual",
        "pipeline": ("59", "59", "projects", "exact", "company_presented", "59 major projects underway in 34 metros across 25 countries", "exact", "high"),
        "revenue": ("2,256", "2.256", "Revenues 2,256 2,225 2,159"),
    },
    "3Q25": {
        "capex": ("1,136", "1136", "Nine Months Ended September 30 2025: Purchases of other property, plant and equipment (2,875); less Six Months Ended June 30 2025 (1,739) = 3Q25 1,136", "true", "partial"),
        "capex_location": "Condensed Consolidated Statements of Cash Flows, Nine Months Ended; derived quarterly actual",
        "pipeline": ("58", "58", "projects", "exact", "company_presented", "58 major projects underway globally, including 12 xScale projects", "exact", "high"),
        "revenue": ("2,316", "2.316", "Revenues 2,316 2,256 2,159"),
    },
    "4Q25": {
        "capex": ("1,436", "1436", "Total Capital Expenditures $987 $750 $989 $1,136 $1,436", "false", "exact"),
        "pipeline": ("52", "52", "projects", "exact", "company_presented", "major expansion projects underway to 52", "partial", "high"),
        "revenue": ("2,420", "2.42", "Revenues 2,420 2,316 2,261"),
        "capex_url": "https://d1io3yog0oux5.cloudfront.net/_9f22c81eceb2edbbc5ca2b7301fbd5b0/equinix/db/2183/27011/earnings_presentation/Equinix+Q4+25+Earnings+Presentation+Final.pdf",
        "capex_location": "Capital Expenditures slide, Total Capital Expenditures quarterly series",
        "capex_caveat": "Q4 release cash flow is Twelve Months Ended only; quarterly capex taken from presentation total capex table and matches FY 4,311M minus 9M 2,875M.",
    },
    "1Q26": {
        "capex": ("(1,256)", "1256", "Three Months Ended March 31 2026: Purchases of other property, plant and equipment (1,256)", "false", "exact"),
        "pipeline": ("~3 GW", "3000", "MW", "approximate", "company_presented_including_unconsolidated", "~3 GW of Developable Capacity Supported by Retail and xScale Land Under Control", "exact", "medium"),
        "revenue": ("2,444", "2.444", "Revenues $2.444 billion ... Revenues 2,444 2,420 2,225"),
        "pipeline_url": "https://d1io3yog0oux5.cloudfront.net/_9f22c81eceb2edbbc5ca2b7301fbd5b0/equinix/db/2183/27031/earnings_presentation/Equinix+Q1+26+Earnings+Presentation+Final.pdf",
        "pipeline_location": "Earnings presentation, developable land-under-control callout",
        "pipeline_caveat": "Q1 2026 release omits global major-project count; GW land-under-control is not MW live capacity and mixes retail plus xScale optionality.",
    },
}

CAPEX_CAVEATS = {
    "2Q24": "GAAP cash-flow PP&E purchases; includes retail and corporate build, not xScale guidance.",
    "3Q24": "GAAP cash-flow PP&E purchases for the quarter.",
    "4Q24": "Quarterly PP&E purchases from Three Months Ended cash flow columns.",
    "1Q25": "GAAP PP&E purchases; separate from non-recurring capex guidance ranges.",
    "2Q25": "Q2 release cash-flow table is Six Months Ended, not standalone quarter; quarterly PP&E derived as 1,739M YTD minus 750M 1Q25 and corroborated by Q4 2025 presentation Total Capital Expenditures series.",
    "3Q25": "Q3 release cash-flow table is Nine Months Ended, not standalone quarter; quarterly PP&E derived as 2,875M YTD minus 1,739M 1H25 and corroborated by Q4 2025 presentation Total Capital Expenditures series.",
    "4Q25": "Q4 release cash flow is Twelve Months Ended only; quarterly capex taken from presentation total capex table and matches FY 4,311M minus 9M 2,875M.",
    "1Q26": "GAAP PP&E purchases; excludes forward non-recurring capex guidance (~$3.8B FY26).",
}

PIPELINE_CAVEATS = {
    "2Q24": "Project-count pipeline metric; not MW live capacity or cabinets delivered.",
    "3Q24": "Includes xScale projects in prose; count is pipeline breadth not delivered MW.",
    "4Q24": "Expansion pipeline project count; not cabinets billed or MW energized.",
    "1Q25": "Includes 12 xScale projects in prose; metric is project count not MW.",
    "2Q25": "Pipeline breadth count including 12 xScale projects; not live capacity.",
    "3Q25": "Land full-build MW cited elsewhere is optionality-not substituted here.",
    "4Q25": "Company cites major expansion projects underway; not MW/cabinets delivered in quarter.",
    "1Q26": "Developable land-under-control metric is approximate GW optionality converted to MW; not MW live capacity, not live energized capacity, and not comparable to project-count quarters without adjustment.",
}


def read_manifest() -> dict[str, dict[str, str]]:
    with MANIFEST.open(newline="", encoding="utf-8") as handle:
        return {row["period"]: row for row in csv.DictReader(handle)}


def base_row(period: str, manifest_row: dict[str, str]) -> dict[str, str]:
    return {
        "company": "EQIX",
        "period": period,
        "is_derived": "false",
        "source_url": manifest_row["source_url"],
    }


def build_rows() -> list[dict[str, str]]:
    manifest = read_manifest()
    rows: list[dict[str, str]] = []

    for period, values in PERIOD_DATA.items():
        if period not in manifest:
            raise KeyError(f"manifest missing period {period}")
        source = manifest[period]

        capex_raw, capex_norm, capex_snippet, capex_derived, capex_status = values["capex"]
        row = base_row(period, source)
        row.update(
            {
                "metric_name": "capex_actuals",
                "raw_value": capex_raw,
                "normalized_value": capex_norm,
                "unit": "USD_millions",
                "value_qualifier": "exact",
                "ownership_basis": "consolidated_company_capex_table",
                "forecast_or_actual": "actual_capex_spend",
                "is_derived": capex_derived,
                "source_url": values.get("capex_url", source["source_url"]),
                "source_location": values.get("capex_location", "Condensed Consolidated Statements of Cash Flows, Three Months Ended"),
                "source_snippet": capex_snippet,
                "snippet_support_status": capex_status,
                "confidence": "high",
                "caveat": values.get("capex_caveat", CAPEX_CAVEATS[period]),
            }
        )
        rows.append(row)

        pipe_raw, pipe_norm, pipe_unit, pipe_qualifier, pipe_basis, pipe_snippet, pipe_status, pipe_confidence = values["pipeline"]
        row = base_row(period, source)
        row.update(
            {
                "metric_name": "future_capacity_pipeline",
                "raw_value": pipe_raw,
                "normalized_value": pipe_norm,
                "unit": pipe_unit,
                "value_qualifier": pipe_qualifier,
                "ownership_basis": pipe_basis,
                "forecast_or_actual": "forecast_pipeline_estimate",
                "source_url": values.get("pipeline_url", source["source_url"]),
                "source_location": values.get("pipeline_location", "Business Highlights"),
                "source_snippet": pipe_snippet,
                "snippet_support_status": pipe_status,
                "confidence": pipe_confidence,
                "caveat": values.get("pipeline_caveat", PIPELINE_CAVEATS[period]),
            }
        )
        rows.append(row)

        revenue_raw, revenue_norm, revenue_snippet = values["revenue"]
        row = base_row(period, source)
        row.update(
            {
                "metric_name": "revenue_conversion",
                "raw_value": revenue_raw,
                "normalized_value": revenue_norm,
                "unit": "USD_billions",
                "value_qualifier": "exact",
                "ownership_basis": "company_presented",
                "forecast_or_actual": "actual_reported_quarter",
                "source_location": "First-Quarter 2026 Results Summary; Condensed Consolidated Statements of Operations"
                if period == "1Q26"
                else "Condensed Consolidated Statements of Operations, Revenues row",
                "source_snippet": revenue_snippet,
                "snippet_support_status": "exact",
                "confidence": "high",
                "caveat": "Revenue reported in USD millions in ops table; summary uses USD billions."
                if period == "1Q26"
                else "Revenue reported in USD millions in source table; normalized to USD billions.",
            }
        )
        rows.append(row)

    return rows


def write_rows(rows: list[dict[str, str]]) -> None:
    with OUTPUT.open("w", newline="", encoding="utf-8") as handle:
        writer = csv.DictWriter(handle, fieldnames=FIELDS)
        writer.writeheader()
        writer.writerows(rows)


def main() -> None:
    write_rows(build_rows())


if __name__ == "__main__":
    main()
