/**
 * Navigator Component
 *
 * Main entry point - renders pages using the framework.
 * Pages return PageResult, Navigator handles rendering.
 */

import { useState, useMemo } from 'react';
import { Box, Text } from 'ink';
import Spinner from 'ink-spinner';
import TextInput from 'ink-text-input';
import { writeFileSync, existsSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { exec, execFile } from 'node:child_process';
import { NavigationProvider, useNavigation } from './lib/context';
import { parseResponse } from './lib/parser';
import { PageRenderer } from './lib/PageRenderer';
import { matchRoute } from './pages/_routes';
import { genericPage } from './pages/GenericPage';
import type { FetchFn, PageComponent, PageResult } from './lib/types';

interface NavigatorProps {
  /** Optional starting URL - if not provided, shows prompt */
  startUrl?: string;
  /** Fetch function */
  fetch: FetchFn;
  /** SAP system name for ADT links (e.g., 'TRL', 'NPL') */
  systemName?: string;
}

/**
 * Open raw XML in IDE (VS Code)
 */
function openXmlInIde(xml: string, url: string): void {
  const safeName = url.replaceAll(/[^a-zA-Z0-9]/g, '_').slice(-50);
  const filename = `adt_${safeName}.xml`;
  const filepath = join(tmpdir(), filename);
  writeFileSync(filepath, xml, 'utf-8');
  exec(`code "${filepath}"`, (error) => {
    if (error) {
      exec(`xdg-open "${filepath}"`);
    }
  });
}

/**
 * Resolve absolute path to a launcher binary from an allow-list of known
 * install locations. Prevents PATH-hijack (S4036) by avoiding bare-name
 * lookups when an absolute path is available. Falls back to the bare name
 * only if none of the known paths exist, so packaged distributions with
 * non-standard layouts still function.
 */
function resolveLauncher(
  candidates: readonly string[],
  fallbackName: string,
): string {
  for (const p of candidates) {
    if (existsSync(p)) return p;
  }
  return fallbackName;
}

const XDG_OPEN = resolveLauncher(
  ['/usr/bin/xdg-open', '/usr/local/bin/xdg-open'],
  'xdg-open',
);
const OPEN_MAC = resolveLauncher(
  ['/usr/bin/open', '/usr/local/bin/open'],
  'open',
);

/**
 * Open in Eclipse ADT
 * Format: adt://[system]/[path]
 * @see https://help.sap.com/docs/abap-cloud/abap-development-tools-user-guide/opening-adt-links
 */
function openInAdt(systemName: string, url: string): void {
  const adtUrl = `adt://${systemName}${url}`;
  // Use execFile (arg array, no shell) to avoid shell-command injection
  // via systemName/url. Try xdg-open (Linux), fall back to open (macOS).
  // Paths resolved above via allow-list to prevent PATH-hijack (S4036).
  execFile(XDG_OPEN, [adtUrl], (error) => {
    if (error) {
      execFile(OPEN_MAC, [adtUrl], (err2) => {
        if (err2) {
          console.error('Failed to open ADT link:', err2.message);
        }
      });
    }
  });
}

/**
 * Inner component that uses navigation context
 */
function NavigatorInner({ systemName }: { systemName?: string }) {
  const { current, loading, error, navigate, back } = useNavigation();

  // Get page result
  const pageResult = useMemo<PageResult | null>(() => {
    if (!current) return null;

    // Try file-based route matching first
    const fileRoute = matchRoute(current.url);
    const pageFn: PageComponent = fileRoute?.page ?? genericPage;

    return pageFn({ url: current.url, response: current.response });
  }, [current]);

  // Handle actions
  const handleAction = (key: string) => {
    if (key === 'openXml' && current) {
      openXmlInIde(current.response.raw, current.url);
    } else if (key === 'openAdt' && current && systemName) {
      openInAdt(systemName, current.url);
    }
  };

  if (loading) {
    return (
      <Box padding={1}>
        <Text color="cyan">
          <Spinner type="dots" />
        </Text>
        <Text> Loading...</Text>
      </Box>
    );
  }

  if (error) {
    return (
      <Box padding={1} flexDirection="column">
        <Text color="red">❌ Error: {error}</Text>
        <Text dimColor>Press Ctrl+C to exit</Text>
      </Box>
    );
  }

  if (!current) {
    return <UrlPrompt onSubmit={navigate} />;
  }

  if (!current || !pageResult) {
    return (
      <Box padding={1}>
        <Text dimColor>No content loaded</Text>
      </Box>
    );
  }

  return (
    <PageRenderer
      result={pageResult}
      onNavigate={navigate}
      onBack={back}
      onAction={handleAction}
    />
  );
}

/**
 * Main Navigator component
 */
export function Navigator({
  startUrl,
  fetch,
  systemName,
}: NavigatorProps): React.ReactNode {
  return (
    <NavigationProvider
      fetch={fetch}
      parseResponse={parseResponse}
      initialUrl={startUrl}
    >
      <NavigatorInner systemName={systemName} />
    </NavigationProvider>
  );
}

/**
 * URL input prompt component
 */
function UrlPrompt({ onSubmit }: { onSubmit: (url: string) => void }) {
  const [url, setUrl] = useState('');

  const handleSubmit = () => {
    if (url.trim()) {
      onSubmit(url.trim());
    }
  };

  return (
    <Box flexDirection="column" padding={1}>
      <Text color="cyan" bold>
        ADT TUI - Hypermedia Navigator
      </Text>
      <Box marginTop={1}>
        <Text>Enter URL: </Text>
        <TextInput value={url} onChange={setUrl} onSubmit={handleSubmit} />
      </Box>
      <Box marginTop={1}>
        <Text dimColor>
          Example: /sap/bc/adt/cts/transportrequests/TRLK900001
        </Text>
      </Box>
    </Box>
  );
}
