#!/usr/bin/env node

/**
 * Figma Tools CLI
 */

import { FigmaClient, parseFigmaUrl, downloadImage } from './figma-client.ts';
import { simplifyDesign } from './simplify.ts';
import type { FigmaNode, FigmaFileResponse, FigmaNodeResponse } from './types.ts';

const API_KEY = process.env.FIGMA_API_KEY;

function showHelp(): void {
  console.log(`
Figma Tools - Fetch and parse Figma design files

Usage:
  figma-tools get <url> [options]       Fetch and simplify Figma file/node
  figma-tools download <url> <dir>      Download images/assets
  figma-tools parse <file> [options]    Parse local JSON file

Commands:

  get <figma-url>
    Fetch a Figma file or specific node. Outputs simplified JSON.
    
    Options:
      --depth N     Limit tree depth (1-4)
      --raw         Output raw API response
      --yaml        Output as YAML
      
    Examples:
      figma-tools get https://www.figma.com/file/ABC123/My-Design
      figma-tools get "https://www.figma.com/file/ABC123/My-Design?node-id=123%3A456" --depth 2
      figma-tools get https://www.figma.com/file/ABC123/My-Design --raw > raw.json

  download <figma-url> <output-dir>
    Download images and assets from a Figma file.
    
    Options:
      --scale N     PNG scale factor (1-4, default: 1)
      --format fmt  Image format: png, svg, or both (default: png)
      
    Examples:
      figma-tools download https://www.figma.com/file/ABC123/My-Design ./assets
      figma-tools download https://www.figma.com/file/ABC123/My-Design ./assets --scale 2

  parse <json-file>
    Simplify a raw Figma API JSON file.
    
    Options:
      --yaml    Output as YAML
      
    Examples:
      figma-tools parse ./raw-figma-response.json
      figma-tools parse ./raw.json --yaml > design.yaml

Setup:
  export FIGMA_API_KEY="your-token-here"
  Get a token from Figma Settings → Personal Access Tokens
`);
}

async function output(data: unknown, useYaml: boolean): Promise<void> {
  if (useYaml) {
    const yaml = await import('js-yaml');
    console.log(yaml.default.dump(data, { indent: 2, lineWidth: 120 }));
  } else {
    console.log(JSON.stringify(data, null, 2));
  }
}

async function getCommand(args: string[]): Promise<void> {
  if (!API_KEY) {
    console.error('Error: FIGMA_API_KEY environment variable required');
    console.error('Get a token from: https://help.figma.com/hc/en-us/articles/8085703771159-Manage-personal-access-tokens');
    process.exit(1);
  }

  const url = args.find((a) => !a.startsWith('--'));
  if (!url) {
    console.error('Error: No URL provided');
    console.error('Usage: figma-tools get <figma-url> [--depth N] [--raw] [--yaml]');
    process.exit(1);
  }

  const depthArg = args.find((a, i) => a === '--depth' && args[i + 1]);
  const depth = depthArg ? parseInt(args[args.indexOf(depthArg) + 1]) : null;
  const raw = args.includes('--raw');
  const yaml = args.includes('--yaml');

  const parsed = parseFigmaUrl(url);
  if (!parsed) {
    console.error('Error: Invalid Figma URL');
    console.error('Expected: https://www.figma.com/file/{fileKey}/{title} or with ?node-id=');
    process.exit(1);
  }

  const client = new FigmaClient(API_KEY);

  let data: FigmaFileResponse | FigmaNodeResponse;
  if (parsed.nodeId) {
    console.error(`Fetching node ${parsed.nodeId} from file ${parsed.fileKey}...`);
    data = await client.getNode(parsed.fileKey, parsed.nodeId, depth);
  } else {
    console.error(`Fetching file ${parsed.fileKey}...`);
    data = await client.getFile(parsed.fileKey, depth);
  }

  if (raw) {
    await output(data, yaml);
  } else {
    console.error('Simplifying response...');
    const simplified = simplifyDesign(data);
    await output(simplified, yaml);
  }
}

async function downloadCommand(args: string[]): Promise<void> {
  if (!API_KEY) {
    console.error('Error: FIGMA_API_KEY environment variable required');
    process.exit(1);
  }

  const url = args.find((a) => !a.startsWith('--'));
  const outputDir = args.filter((a) => !a.startsWith('--'))[1];

  if (!url || !outputDir) {
    console.error('Error: URL and output directory required');
    console.error('Usage: figma-tools download <figma-url> <output-dir> [--scale N] [--format png|svg]');
    process.exit(1);
  }

  const scaleArg = args.find((a, i) => a === '--scale' && args[i + 1]);
  const scale = scaleArg ? parseInt(args[args.indexOf(scaleArg) + 1]) : 1;
  const formatArg = args.find((a, i) => a === '--format' && args[i + 1]);
  const format = formatArg ? args[args.indexOf(formatArg) + 1] : 'png';

  const parsed = parseFigmaUrl(url);
  if (!parsed) {
    console.error('Error: Invalid Figma URL');
    process.exit(1);
  }

  const client = new FigmaClient(API_KEY);

  console.error('Fetching file structure...');
  const fileData = await client.getFile(parsed.fileKey, 3);

  const imageNodes: Array<{ id: string; name: string; imageRef?: string }> = [];
  const svgNodes: Array<{ id: string; name: string }> = [];

  function sanitizeFilename(name: string): string {
    return name
      .replace(/[^a-zA-Z0-9\-_./\s]/g, '')
      .replace(/\s+/g, '_')
      .substring(0, 100);
  }

  function collectNodes(nodes: FigmaNode[], parentPath = ''): void {
    for (const node of nodes) {
      const currentPath = parentPath ? `${parentPath}/${node.name}` : node.name;

      if (node.fills) {
        const fills = Array.isArray(node.fills) ? node.fills : [node.fills];
        for (const fill of fills) {
          if (fill?.type === 'IMAGE' && fill.imageRef) {
            imageNodes.push({
              id: node.id,
              name: sanitizeFilename(currentPath) + '.png',
              imageRef: fill.imageRef,
            });
          }
        }
      }

      if (
        ['VECTOR', 'BOOLEAN_OPERATION', 'STAR', 'POLYGON', 'LINE', 'ELLIPSE', 'RECTANGLE'].includes(
          node.type
        )
      ) {
        svgNodes.push({
          id: node.id,
          name: sanitizeFilename(currentPath) + '.svg',
        });
      }

      if (node.children) {
        collectNodes(node.children, currentPath);
      }
    }
  }

  let nodesToProcess: FigmaNode[];
  if (parsed.nodeId) {
    // fileData is FigmaNodeResponse when we requested a specific node
    const nodeResponse = fileData as unknown as { nodes?: Record<string, { document: FigmaNode }> };
    nodesToProcess = nodeResponse.nodes?.[parsed.nodeId]?.document?.children || [];
  } else {
    nodesToProcess = fileData.document?.children || [];
  }

  collectNodes(nodesToProcess);

  console.error(`Found ${imageNodes.length} image fills, ${svgNodes.length} exportable nodes`);

  const results: string[] = [];

  if ((format === 'png' || format === 'both') && (imageNodes.length > 0 || svgNodes.length > 0)) {
    const pngIds = [
      ...imageNodes.map((n) => n.id),
      ...svgNodes.map((n) => n.id),
    ];

    console.error(`Downloading ${pngIds.length} PNGs at ${scale}x...`);
    const images = await client.getImages(parsed.fileKey, pngIds, 'png', scale);

    for (const [nodeId, imageUrl] of Object.entries(images)) {
      if (imageUrl) {
        const node = [...imageNodes, ...svgNodes].find((n) => n.id === nodeId);
        if (node) {
          const fileName = node.name.endsWith('.png') ? node.name : `${node.name}.png`;
          const path = await downloadImage(imageUrl, outputDir, fileName);
          results.push(path);
        }
      }
    }
  }

  if ((format === 'svg' || format === 'both') && svgNodes.length > 0) {
    console.error(`Downloading ${svgNodes.length} SVGs...`);
    const images = await client.getImages(
      parsed.fileKey,
      svgNodes.map((n) => n.id),
      'svg'
    );

    for (const [nodeId, imageUrl] of Object.entries(images)) {
      if (imageUrl) {
        const node = svgNodes.find((n) => n.id === nodeId);
        if (node) {
          const path = await downloadImage(imageUrl, outputDir, node.name);
          results.push(path);
        }
      }
    }
  }

  console.error(`\nDownloaded ${results.length} files to: ${outputDir}`);
  for (const path of results) {
    console.log(path);
  }
}

async function parseCommand(args: string[]): Promise<void> {
  const fs = await import('fs');

  const filePath = args.find((a) => !a.startsWith('--'));
  if (!filePath) {
    console.error('Error: No file path provided');
    console.error('Usage: figma-tools parse <json-file> [--yaml]');
    process.exit(1);
  }

  const yaml = args.includes('--yaml');

  if (!fs.existsSync(filePath)) {
    console.error(`Error: File not found: ${filePath}`);
    process.exit(1);
  }

  const raw = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
  console.error('Simplifying...');
  const simplified = simplifyDesign(raw);
  await output(simplified, yaml);
}

async function main(): Promise<void> {
  const args = process.argv.slice(2);
  const command = args[0];

  if (!command || command === '--help' || command === '-h') {
    showHelp();
    process.exit(0);
  }

  const commandArgs = args.slice(1);

  try {
    switch (command) {
      case 'get':
        await getCommand(commandArgs);
        break;
      case 'download':
        await downloadCommand(commandArgs);
        break;
      case 'parse':
        await parseCommand(commandArgs);
        break;
      default:
        console.error(`Unknown command: ${command}`);
        showHelp();
        process.exit(1);
    }
  } catch (err) {
    console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);
    process.exit(1);
  }
}

main();
