#!/usr/bin/env python3
"""Generator script for @keluargamart/permissions.
Reads apps/backend/internal/auth/catalog.go and regenerates:
  1. packages/permissions/src/index.js (ESM constants and can() helper)
  2. packages/permissions/src/index.d.ts (TypeScript declaration)
  3. packages/permissions/src/permissions.txt (raw lines for inspection/diff)
"""
import os
import re
import sys

KEY = re.compile(r'"([a-z_][a-z0-9_]*(?:\.[a-z0-9_-]+)+)"')

def main():
    root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    catalog_path = os.path.join(root, "apps", "backend", "internal", "auth", "catalog.go")
    out_dir = os.path.join(root, "packages", "permissions", "src")
    os.makedirs(out_dir, exist_ok=True)

    if not os.path.exists(catalog_path):
        sys.exit(f"Error: Backend catalog not found at {catalog_path}")

    with open(catalog_path, encoding="utf-8") as f:
        source = f.read()

    keys = {m.group(1) for m in KEY.finditer(source) if not m.group(1).endswith(".")}
    sorted_keys = sorted(keys)
    if not sorted_keys:
        sys.exit("Error: No permission keys found in catalog.go")

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

    # 2. index.js
    js_path = os.path.join(out_dir, "index.js")
    keys_json = ",\n  ".join(f'"{k}"' for k in sorted_keys)
    js_content = """// AUTO-GENERATED from apps/backend/internal/auth/catalog.go — DO NOT EDIT DIRECTLY.
// Run: pnpm permissions:generate

/**
 * Standard System Roles in KeluargaMart
 */
export const ROLES = [
  'admin',
  'owner',
  'gm',
  'bm',
  'spv',
  'sales',
  'store_manager',
  'cashier',
  'buyer',
  'finance',
  'finance_head',
  'warehouse',
  'hr_manager',
  'hr_staff',
  'employee',
  'system',
];

/**
 * Canonical List of All Validated Permissions (Total: """ + str(len(sorted_keys)) + """)
 */
export const ALL_PERMISSIONS = [
  """ + keys_json + """
];

export const ALL_PERMISSIONS_SET = new Set(ALL_PERMISSIONS);

/**
 * Fail-closed RBAC permission check.
 * Supports:
 * - Admin/Owner bypass (if user or role has superuser rights)
 * - Wildcard permission match (e.g. 'hr.employees.*' covers 'hr.employees.create')
 * - Map format from /auth/me: { 'sales.*': true, 'system.users.view': true }
 * - Array format: ['system.users.view', 'sales.*']
 *
 * @param {string[] | Record<string, boolean> | null | undefined} perms
 * @param {string} perm
 * @param {string} [role]
 * @returns {boolean}
 */
export function can(perms, perm, role = null) {
  if (!perm || typeof perm !== 'string') return false;
  if (role === 'admin' || role === 'owner') return true;

  if (Array.isArray(perms)) {
    if (perms.includes('*') || perms.includes('admin') || perms.includes('owner')) return true;
    return perms.some((p) => p === perm || (p.endsWith('.*') && perm.startsWith(p.slice(0, -1))));
  }

  if (perms && typeof perms === 'object') {
    if (perms['*'] === true) return true;
    if (perms[perm] === true) return true;
    return Object.entries(perms).some(([k, v]) => v && k.endsWith('*') && perm.startsWith(k.slice(0, -1)));
  }

  return false;
}

/**
 * Checks if a user has a specific role.
 *
 * @param {string[] | string | null | undefined} userRoles
 * @param {string} role
 * @returns {boolean}
 */
export function hasRole(userRoles, role) {
  if (!userRoles) return false;
  if (userRoles === role) return true;
  if (Array.isArray(userRoles)) {
    if (userRoles.includes('admin') || userRoles.includes('owner')) return true;
    return userRoles.includes(role);
  }
  return false;
}
"""
    with open(js_path, "w", encoding="utf-8") as f:
        f.write(js_content)

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

export declare const ROLES: readonly string[];
export declare type Role = typeof ROLES[number];

export declare const ALL_PERMISSIONS: readonly string[];
export declare type Permission = typeof ALL_PERMISSIONS[number];

export declare const ALL_PERMISSIONS_SET: ReadonlySet<string>;

export declare function can(
  perms: readonly string[] | Record<string, boolean> | null | undefined,
  perm: string,
  role?: string | null
): boolean;

export declare function hasRole(
  userRoles: readonly string[] | string | null | undefined,
  role: string
): boolean;
""")

    print(f"Permissions generated successfully: {len(sorted_keys)} keys written to {out_dir}")

if __name__ == "__main__":
    main()
