#!/usr/bin/env python3
"""Generator script for @keluargamart/contracts.
Reads apps/backend/docs/openapi.yaml and regenerates:
  1. packages/contracts/src/routes.js (ESM array of "METHOD /path")
  2. packages/contracts/src/routes.d.ts (TypeScript declaration)
  3. packages/contracts/src/routes.txt (raw lines for inspection/diff)
"""
import os
import sys
import yaml

VERBS = ("get", "post", "put", "patch", "delete")

def main():
    root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    openapi_path = os.path.join(root, "apps", "backend", "docs", "openapi.yaml")
    out_dir = os.path.join(root, "packages", "contracts", "src")
    os.makedirs(out_dir, exist_ok=True)

    if not os.path.exists(openapi_path):
        sys.exit(f"Error: OpenAPI spec not found at {openapi_path}")

    with open(openapi_path, encoding="utf-8") as f:
        spec = yaml.safe_load(f)

    routes = set()
    for path, ops in (spec.get("paths") or {}).items():
        if not isinstance(ops, dict):
            continue
        for verb in ops:
            if verb.lower() in VERBS:
                routes.add(f"{verb.lower()} {path}")

    sorted_routes = sorted(routes)
    if not sorted_routes:
        sys.exit("Error: No routes found in OpenAPI spec")

    # 1. routes.txt
    txt_path = os.path.join(out_dir, "routes.txt")
    with open(txt_path, "w", encoding="utf-8") as f:
        f.write("\n".join(sorted_routes) + "\n")

    # 2. routes.js
    js_path = os.path.join(out_dir, "routes.js")
    routes_json = ",\n  ".join(f'"{r}"' for r in sorted_routes)
    js_content = """// AUTO-GENERATED from apps/backend/docs/openapi.yaml — DO NOT EDIT DIRECTLY.
// Run: pnpm contracts:generate

export const API_PREFIX = '/api/v1';

export const BACKEND_ROUTES = [
  """ + routes_json + """
];

export const BACKEND_ROUTES_SET = new Set(BACKEND_ROUTES);

/**
 * Normalizes an API path for route matching.
 * Collapses interpolated path params into a single /1 placeholder.
 */
export function normalizePath(path) {
  const withPrefix = path.startsWith('/api/') ? path : `${API_PREFIX}${path.startsWith('/') ? '' : '/'}${path}`;
  return withPrefix
    .replace(/\\/\\d+(\\/|$)/g, '/1$1')
    .replace(/\\/\\{[^\\}]+\\}/g, '/1');
}

/**
 * Verifies if an endpoint is declared in the backend route catalog.
 */
export function hasBackendRoute(verb, path) {
  const normalizedVerb = verb.toLowerCase();
  const normalizedP = normalizePath(path);
  return BACKEND_ROUTES.some((r) => {
    const [rVerb, rPath] = r.split(' ');
    if (rVerb !== normalizedVerb) return false;
    const normalizedRPath = normalizePath(rPath);
    return normalizedRPath === normalizedP;
  });
}
"""
    with open(js_path, "w", encoding="utf-8") as f:
        f.write(js_content)

    # 3. routes.d.ts
    dts_path = os.path.join(out_dir, "routes.d.ts")
    with open(dts_path, "w", encoding="utf-8") as f:
        f.write("""// AUTO-GENERATED from apps/backend/docs/openapi.yaml — DO NOT EDIT DIRECTLY.

export declare const API_PREFIX: string;
export declare const BACKEND_ROUTES: readonly string[];
export declare const BACKEND_ROUTES_SET: ReadonlySet<string>;
export declare function normalizePath(path: string): string;
export declare function hasBackendRoute(verb: string, path: string): boolean;
""")

    print(f"Contracts generated successfully: {len(sorted_routes)} routes written to {out_dir}")

if __name__ == "__main__":
    main()
