import { L as LLMClient, s as stepCountIs, g as getComponentInfoTool, a as searchComponentsTool, l as listComponentsTool } from "./component-tools-DSuKjvQo.js";
import { loadDesignEngineer, discoverAllComponents } from "./cli/component-discovery.js";
import { D as DEFAULT_MODEL } from "./models-Cfqixfch.js";
class CodeCleaner {
  /**
   * Remove markdown fences, normalize spacing, and clean LLM artifacts
   *
   * This combines the best practices from both screen-composer and generate-screen
   * implementations to provide comprehensive code cleaning.
   */
  clean(code) {
    if (typeof code !== "string") return code;
    let cleaned = code.trim();
    cleaned = cleaned.replaceAll(
      /```[a-zA-Z0-9-]*\s*\n?([\s\S]*?)\n?```/g,
      "$1"
    );
    cleaned = cleaned.replaceAll("```", "");
    cleaned = cleaned.replaceAll(
      /`var\(--([^`]*?)\$\{([^}]+)\}([^`]*?)\)`/g,
      (_m, pre, expr, post) => `"var(--${pre}" + ${expr} + "${post})"`
    );
    cleaned = cleaned.replaceAll(/\n{3,}/g, "\n\n");
    const firstImportIdx = cleaned.search(/^\s*import\s+/m);
    if (firstImportIdx > 0) {
      cleaned = cleaned.slice(firstImportIdx);
    }
    cleaned = cleaned.split("\n").filter((line) => !line.includes("```")).join("\n").trim();
    return cleaned;
  }
  /**
   * Extract specific sections from generated code
   */
  extractImports(code) {
    const importMatch = code.match(/import[\s\S]*?from ['"][@\w/-]+['"];?/gm);
    return importMatch ? importMatch.join("\n") : "";
  }
  /**
   * Extract type definitions from generated code
   */
  extractTypes(code) {
    const typeMatch = code.match(
      /(?:interface|type)\s+\w+[\s\S]*?(?=\n(?:interface|type|export|const))/gm
    );
    return typeMatch ? typeMatch.join("\n\n") : void 0;
  }
}
class PromptBuilder {
  designEngineerPrompt;
  constructor() {
    const fullTemplate = loadDesignEngineer();
    const separatorIndex = fullTemplate.indexOf("\n---\n");
    this.designEngineerPrompt = separatorIndex !== -1 ? fullTemplate.substring(0, separatorIndex).trim() : fullTemplate;
  }
  /**
   * Get the design engineer prompt (design guidelines only)
   */
  getDesignEngineerPrompt() {
    return this.designEngineerPrompt;
  }
  /**
   * Format component information for LLM context
   */
  formatComponentDocs(componentInfo) {
    return componentInfo.map((c) => {
      if ("type" in c && c.type === "group") {
        const componentsArray = Array.isArray(c.components) ? c.components : Object.entries(c.components).map(([id, comp]) => ({
          id,
          ...comp
        }));
        const comps = componentsArray.map((comp) => {
          const lines = [`  - ${comp.name}`, `    Import: ${comp.import}`];
          if (comp.description)
            lines.push(`    Description: ${comp.description}`);
          return lines.join("\n");
        }).join("\n\n");
        return [
          `${c.name} (${c.category})`,
          c.description ? `Description: ${c.description}` : "",
          "Components:",
          comps
        ].filter(Boolean).join("\n");
      } else {
        const info = c;
        const lines = [
          `${info.name} (${info.category})`,
          `Import: ${info.import}`
        ];
        if (info.description) lines.push(`Description: ${info.description}`);
        if (info.props) {
          const entries = Object.entries(info.props);
          const required = entries.filter(([, p]) => p.required).map(
            ([name, p]) => `${name}: ${p.type ?? "unknown"}`
          );
          const optional = entries.filter(([, p]) => !p.required).map(([name]) => name);
          if (required.length)
            lines.push(`Required Props: ${required.join(", ")}`);
          if (optional.length) {
            const head = optional.slice(0, 10).join(", ");
            const tail = optional.length > 10 ? ", ..." : "";
            lines.push(`Optional Props: ${head}${tail}`);
          }
        }
        if (info.example) lines.push(`Example: ${info.example}`);
        return lines.join("\n");
      }
    }).join("\n\n---\n\n");
  }
  /**
   * Build a component import map showing correct import paths and props
   */
  buildComponentImportMap(componentInfo) {
    return componentInfo.map((c) => {
      if ("type" in c && c.type === "group") {
        const componentsArray = Array.isArray(c.components) ? c.components : Object.entries(c.components).map(([id, comp]) => ({
          id,
          ...comp
        }));
        return componentsArray.map((comp) => `${comp.name}: ${comp.import}`).join("\n");
      } else {
        const componentInfo2 = c;
        const props = componentInfo2.props ? Object.keys(componentInfo2.props).filter((p) => !p.includes("...")).join(", ") : "standard HTML props";
        return `${componentInfo2.name}: ${componentInfo2.import} // Key props: ${props}`;
      }
    }).join("\n");
  }
}
class CommandExecutor {
  llmClient;
  codeCleaner;
  promptBuilder;
  defaultLLMOptions;
  constructor(options = {}) {
    this.llmClient = new LLMClient();
    this.codeCleaner = new CodeCleaner();
    this.promptBuilder = new PromptBuilder();
    this.defaultLLMOptions = options.llm || {};
  }
  /**
   * Main execution method - Template Method pattern
   *
   * Defines the algorithm structure, calling abstract methods
   * that subclasses must implement.
   */
  async execute(input, options = {}) {
    await this.llmClient.initialize();
    this.validateInput(input);
    const context = await this.prepareContext(input);
    const mergedOptions = { ...this.defaultLLMOptions, ...options };
    const rawResult = await this.llmClient.generate(context, mergedOptions);
    const processed = await this.processResult(rawResult, input);
    return processed;
  }
}
class ScreenExecutor extends CommandExecutor {
  constructor() {
    super({
      llm: {
        model: "claude-haiku-4-5"
      }
    });
  }
  /**
   * Override execute to handle two-phase generation with different tools
   */
  async execute(input, options = {}) {
    await this.llmClient.initialize();
    this.validateInput(input);
    const planResult = await this.generatePlan(input);
    const context = this.buildContextWithPlan(input, planResult);
    const mergedOptions = {
      ...this.defaultLLMOptions,
      ...options,
      tools: {
        get_component_info: getComponentInfoTool
      },
      stopWhen: stepCountIs(3)
    };
    const rawResult = await this.llmClient.generate(context, mergedOptions);
    const processed = await this.processResult(rawResult, input);
    processed.plan = planResult.plan;
    processed.componentNames = planResult.componentNames;
    return processed;
  }
  validateInput(input) {
    if (!input.prompt || typeof input.prompt !== "string") {
      throw new Error("Screen prompt is required and must be a string");
    }
    if (input.prompt.trim().length === 0) {
      throw new Error("Screen prompt cannot be empty");
    }
  }
  async prepareContext() {
    throw new Error("prepareContext should not be called directly");
  }
  async processResult(rawResult, input) {
    const code = this.codeCleaner.clean(rawResult);
    return {
      code,
      plan: "",
      componentNames: [],
      schema: input.schema
    };
  }
  getCacheKey(input) {
    return `${input.prompt}:${input.schema || "no-schema"}:${input.model || "default"}`;
  }
  async generatePlan(input) {
    const allComponents = discoverAllComponents();
    const designEngineerPrompt = this.promptBuilder.getDesignEngineerPrompt();
    const planPromptParts = [
      `You are a design engineer planning a React screen using the Glide UI component library.`,
      "",
      designEngineerPrompt,
      "",
      "---",
      "",
      `USER REQUEST: Create a screen for: ${input.prompt}`,
      ""
    ];
    if (input.schema) {
      planPromptParts.push(
        "---",
        "",
        "DATA SCHEMA:",
        "",
        "The screen will work with data matching this TypeScript interface:",
        "",
        input.schema,
        "",
        "When selecting components, consider this schema:",
        "- Use form components for input/editing scenarios",
        "- Use data display components (tables, lists, cards) for showing collections",
        "- Use detail view patterns for single object displays",
        "- Consider the data structure when choosing layout components",
        ""
      );
    }
    planPromptParts.push(
      "---",
      "",
      "AVAILABLE TOOLS:",
      "",
      "You have access to tools for discovering components:",
      "- list_components: Browse all available components with categories and descriptions",
      "- search_components: Search for components by keyword (e.g., 'form input', 'table', 'chart')",
      "",
      "Use these tools to explore and select appropriate components for the screen.",
      "",
      "---",
      "",
      "TASK: Create a detailed plan for this screen that includes:",
      "1. Use the tools to discover relevant components for this screen",
      "2. Create a structured description of the screen layout and functionality",
      "3. Provide a list of component IDs that will be needed to build this screen",
      "4. Explain how these components will be arranged and interact",
      "",
      "Respond in the following markdown format:",
      "",
      "## Plan",
      "",
      "Detailed description of the screen...",
      "",
      "## Components",
      "",
      "- ComponentName1",
      "- ComponentName2",
      "",
      "IMPORTANT: Use exact component names (PascalCase like 'Button', 'Input', 'DataTable') as returned by list_components tool.",
      "Return ONLY markdown with exactly two sections: ## Plan and ## Components."
    );
    const planPrompt = planPromptParts.join("\n");
    const rawPlan = await this.llmClient.generate(
      { prompt: planPrompt },
      {
        model: input.model ?? DEFAULT_MODEL["anthropic"],
        maxTokens: 2e3,
        tools: {
          list_components: listComponentsTool,
          search_components: searchComponentsTool
        },
        stopWhen: stepCountIs(5)
      }
    );
    return this.extractPlanFromResponse(rawPlan, allComponents);
  }
  /**
   * Parse markdown plan from LLM or heuristically recover component names
   */
  extractPlanFromResponse(response, allComponents) {
    const cleaned = response.trim();
    const planMatch = cleaned.match(
      /##\s*Plan\s*\n([\s\S]*?)(?=##\s*Components|$)/i
    );
    const planText = planMatch ? planMatch[1].trim() : "";
    const componentsMatch = cleaned.match(/##\s*Components\s*\n([\s\S]*?)$/i);
    const componentsList = componentsMatch ? componentsMatch[1].trim() : "";
    const componentNames = componentsList.split("\n").map((line) => line.trim()).filter((line) => line.startsWith("-") || line.startsWith("*")).map((line) => line.replace(/^[-*]\s*/, "").trim()).filter(Boolean);
    if (componentNames.length === 0) {
      const set = /* @__PURE__ */ new Set();
      const byLower = new Map(
        allComponents.map((c) => [c.name.toLowerCase(), c.name])
      );
      const hay = cleaned.toLowerCase();
      for (const [k, original] of byLower.entries()) {
        const re = new RegExp(`\\b${escapeRegex(k)}\\b`, "i");
        if (re.test(hay)) set.add(original);
      }
      return { plan: planText || cleaned, componentNames: [...set] };
    }
    return { plan: planText || cleaned, componentNames };
  }
  /**
   * Build final generation context using the plan + tool access for component docs
   */
  buildContextWithPlan(input, planResult) {
    const designEngineerPrompt = this.promptBuilder.getDesignEngineerPrompt();
    const promptParts = [
      `You are a design engineer creating a complete React screen component using the Glide UI component library.`,
      "",
      designEngineerPrompt,
      "",
      "---",
      "",
      `USER REQUEST: Create a screen for: ${input.prompt}`,
      ""
    ];
    if (input.schema) {
      promptParts.push(
        "---",
        "",
        "DATA SCHEMA:",
        "",
        "The screen should work with data matching this TypeScript interface:",
        "",
        input.schema,
        "",
        "Please:",
        "1. Include this interface in the generated code",
        "2. Generate mock data that matches this schema structure in the loader function",
        "3. Use the schema to inform the component structure and data display",
        ""
      );
    }
    promptParts.push(
      "---",
      "",
      "SCREEN PLAN:",
      "",
      planResult.plan,
      "",
      "---",
      "",
      "COMPONENT DOCUMENTATION:",
      "",
      "CRITICAL - Call get_component_info EXACTLY ONCE with ALL component IDs:",
      `Components from plan: ${JSON.stringify(planResult.componentNames)}`,
      "",
      `You MUST call: get_component_info({ componentIds: ${JSON.stringify(planResult.componentNames)} })`,
      "",
      "WORKFLOW:",
      "1. Call get_component_info with the array above (SINGLE call)",
      "2. Read all returned documentation",
      "3. Generate complete screen code",
      "",
      "---",
      "",
      "SCREEN GENERATION REQUIREMENTS:"
    );
    const prompt = [
      ...promptParts,
      "",
      // Critical React Router structure requirements (kept from original)
      `CRITICAL - CORRECT CODE STRUCTURE:
Your code MUST follow this exact import pattern - these imports are REQUIRED and MUST be first:

// STEP 1: React Router imports - REQUIRED, MUST BE FIRST, MUST BE BOTH
// These TWO imports MUST be the VERY FIRST lines of your file, before ANY other imports:
import { useLoaderData } from "react-router";
import type { LoaderFunctionArgs } from "react-router";
// NOTE: You MUST have BOTH of these imports. Do NOT skip either one.
// NOTE: Use "import type { ... }" NOT "import { type ... }" for the type import

// STEP 2: React imports (after React Router imports)
import React, { useState, useMemo } from "react";

// STEP 3: @glide/glide-ui component imports (after React Router and React imports)
import { ScreenWrapper } from "@glide/glide-ui/chrome";
// ... other @glide/glide-ui imports

CRITICAL WARNINGS:
- BOTH React Router imports are REQUIRED - do NOT skip either one
- These MUST be the FIRST two lines of your file
- Use "import type { LoaderFunctionArgs }" NOT "import { type LoaderFunctionArgs }"
- Do NOT put these imports after @glide/glide-ui imports

interface ScreenData {
  // your data structure - use proper types, NEVER use 'any'
}

export async function loader(args: LoaderFunctionArgs): Promise<ScreenData> {
  // loader implementation - return actual data (will be wrapped in Promise automatically)
  // NOTE: loader is a NAMED export, NOT default export
  return {
    // actual data structure matching ScreenData interface
  };
}

export default function YourScreen() {
  // NOTE: This is the ONLY default export in the file
  const data = useLoaderData<typeof loader>();
  // For colors, use Tailwind classes or regular strings, NOT template literals with var()
  return (
    <ScreenWrapper>
      {/* actual screen content */}
    </ScreenWrapper>
  );
}

CRITICAL MISTAKES TO AVOID:
- NEVER use arrow function: export const loader = ...
- MUST use function declaration: export async function loader(...)
- NEVER export loader as default
- ONLY the component should be default export
- EXACTLY one default export
- NEVER manually call loader()
- MUST use useLoaderData<typeof loader>()
- NEVER re-implement React Router hooks
- NEVER use 'any'
- Wrap content in <ScreenWrapper />
- Use Tailwind / component props for colors (no template-literal CSS vars)

CRITICAL - IMPORT REQUIREMENTS (MUST FOLLOW EXACTLY):
- Line 1: import { useLoaderData } from "react-router";
- Line 2: import type { LoaderFunctionArgs } from "react-router";
- Then React
- Then @glide/glide-ui imports
- Use "import type" for type-only imports
- All imports must be at the very top

GENERATION REQUIREMENTS:
- Output ONLY valid TypeScript/TSX code, no markdown
- Start with imports, end with component code
- No explanations or comments outside of code
- Generate the complete screen now.`
    ].join("\n");
    return { prompt };
  }
}
function escapeRegex(s) {
  return s.replaceAll(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
const SUPPORTED_MODELS = [
  "claude-haiku-4-5",
  "claude-sonnet-4-5",
  "claude-opus-4-1"
];
function isSupportedModel(m) {
  return SUPPORTED_MODELS.includes(m);
}
class ScreenComposer {
  executor;
  constructor() {
    this.executor = new ScreenExecutor();
  }
  async compose(prompt, options = {}) {
    const model = options.model ?? "claude-haiku-4-5";
    if (!isSupportedModel(model)) {
      throw new Error(
        `Unsupported model: ${model}. Supported models: ${SUPPORTED_MODELS.join(", ")}`
      );
    }
    const result = await this.executor.execute(
      { prompt, model, maxTokens: options.maxTokens },
      { model }
    );
    return { code: result.code };
  }
}
export {
  CodeCleaner as C,
  PromptBuilder as P,
  ScreenExecutor as S,
  ScreenComposer as a,
  CommandExecutor as b
};
