// @bun
import {
  userInput
} from "./chunk-tefbm840.js";
import {
  resolveCommandContext
} from "./chunk-2jcqy5j6.js";
import {
  ADK_LOGO_LINE1,
  ADK_LOGO_LINE2
} from "./chunk-9e2nksab.js";
import {
  bold,
  box,
  fg,
  getActiveTheme,
  mount,
  router,
  signal,
  t,
  text
} from "./chunk-m2h26j5f.js";
import {
  createCliLogger
} from "./chunk-t993tmz7.js";
import {
  AdkError,
  AgentProject,
  ConfigManager,
  coerceConfigValue
} from "./chunk-7krp2mgz.js";

// src/utils/config-validator.ts
async function resolveConfigContext(options) {
  let project = options.project;
  let credentials = options.credentials;
  let client = options.client;
  if (!project || !credentials || options.createClient && !client) {
    const context = await resolveCommandContext({
      cwd: options.projectPath,
      target: options.isProd ? "prod" : "dev",
      require: options.createClient ? ["workspace"] : [],
      createClient: options.createClient
    });
    project ??= context.project;
    credentials ??= context.credentials;
    client ??= context.client;
  }
  if (!project || !credentials) {
    throw new AdkError({
      code: "CONFIG_VALIDATION_FAILED",
      message: "Unable to resolve project credentials for configuration validation.",
      expected: true
    });
  }
  return {
    project,
    credentials,
    ...client ? { client } : {}
  };
}
async function validateRemoteConfig(projectPath, botId, configSchema, options = {}) {
  try {
    const { client } = await resolveConfigContext({
      projectPath,
      isProd: options.isProd ?? true,
      project: options.project,
      credentials: options.credentials,
      client: options.client,
      createClient: true
    });
    if (!client) {
      throw new AdkError({
        code: "CONFIG_VALIDATION_FAILED",
        message: "Unable to create a client for remote configuration validation.",
        expected: true
      });
    }
    const { bot } = await client.getBot({ id: botId });
    const remoteConfig = bot.configuration?.data || {};
    const result = configSchema.safeParse(remoteConfig);
    if (result.success) {
      return { valid: true, errors: [] };
    }
    const errors = [];
    for (const issue of result.error.issues) {
      const key = issue.path.join(".");
      errors.push(`${key}: ${issue.message}`);
    }
    return { valid: false, errors };
  } catch (error) {
    return { valid: false, errors: [`Failed to fetch remote configuration: ${error}`] };
  }
}
async function validateAndPromptConfig(options) {
  const { projectPath, isProd, interactive = true, botId } = options;
  const project = options.project ?? await AgentProject.load(projectPath);
  const configSchema = project.config?.configuration?.schema;
  if (!configSchema) {
    return { valid: true, config: {}, errors: [] };
  }
  if (!configSchema?._def?.typeName || configSchema._def.typeName !== "ZodObject") {
    throw new AdkError({
      code: "INVALID_CONFIG_SCHEMA",
      message: "Configuration schema must be a z.object()",
      expected: true
    });
  }
  const logger = createCliLogger();
  const { credentials, client } = await resolveConfigContext({
    projectPath,
    isProd,
    project,
    credentials: options.credentials,
    client: options.client,
    createClient: !!botId
  });
  const currentBotId = botId || (isProd ? project.agentInfo?.botId : project.agentInfo?.devId);
  if (!currentBotId) {
    logger.warn(`\u26A0 No ${isProd ? "production" : "development"} bot ID found`);
    return { valid: false, config: {}, errors: ["No bot ID found"] };
  }
  const configManager = new ConfigManager(currentBotId, {
    project,
    credentials
  });
  if (botId) {
    const remoteValidation = await validateRemoteConfig(projectPath, botId, configSchema, {
      isProd,
      project,
      credentials,
      client
    });
    if (!remoteValidation.valid) {
      const actualErrors = remoteValidation.errors.filter((error) => !error.includes("Required") && !error.includes("required"));
      if (actualErrors.length > 0) {
        logger.warn(`
\u26A0 Remote bot configuration has invalid values:`);
        for (const error of actualErrors) {
          logger.error(`  \u2022 ${error}`);
        }
        logger.info(`
Please update the bot configuration in Botpress Studio.
`, "gray");
      }
    }
  }
  const validation = await configManager.validate(configSchema);
  if (validation.valid) {
    const config2 = await configManager.getAll();
    if (interactive) {
      logger.info(`\u2713 Configuration validated successfully
`, "green");
    }
    return { valid: true, config: config2, errors: [] };
  }
  if (!interactive) {
    return {
      valid: false,
      config: await configManager.getAll(),
      errors: validation.errors
    };
  }
  const shape = configSchema.shape;
  const allKeys = Object.keys(shape);
  const currentConfig = await configManager.getAll();
  const validKeys = [];
  const invalidKeys = [];
  const missingKeys = [];
  for (const key of allKeys) {
    const fieldSchema = shape[key];
    const currentValue = currentConfig[key];
    const description = fieldSchema.description;
    if (currentValue === undefined) {
      missingKeys.push({ key, description });
    } else {
      const result = fieldSchema.safeParse(currentValue);
      if (result.success) {
        validKeys.push(key);
      } else {
        invalidKeys.push({
          key,
          error: result.error.issues[0]?.message || "Invalid value",
          description
        });
      }
    }
  }
  const keysToPrompt = [
    ...missingKeys.map((m) => ({ ...m, error: undefined })),
    ...invalidKeys.map((i) => ({ key: i.key, description: i.description, error: i.error }))
  ];
  if (keysToPrompt.length > 0) {
    await promptForAllConfigValues({
      keys: keysToPrompt,
      validKeys,
      configManager,
      shape,
      schema: configSchema,
      isProd
    });
  }
  const finalValidation = await configManager.validate(configSchema);
  const config = await configManager.getAll();
  if (!finalValidation.valid) {
    return {
      valid: false,
      config,
      errors: finalValidation.errors
    };
  }
  if (interactive) {
    logger.info(`
\u2713 Configuration validated successfully
`, "green");
  }
  return { valid: true, config, errors: [] };
}
function configPromptModal(renderer, scope, deps) {
  const { keys, validKeys, shape, isProd, configManager, onComplete, onError } = deps;
  const theme = getActiveTheme();
  const pendingValues = {};
  const index = signal(0);
  let saveStarted = false;
  const saveAll = async () => {
    try {
      const currentConfig = await configManager.getAll();
      await configManager.save({ ...currentConfig, ...pendingValues });
      onComplete();
    } catch (error) {
      onError(error instanceof Error ? error : new Error(String(error)));
    }
  };
  const logoLines = () => box(renderer, { flexDirection: "column", marginBottom: 1 }, [
    text(renderer, t`${fg(theme.accent.purple)(bold(` ${ADK_LOGO_LINE1}`))}`),
    text(renderer, t`${fg(theme.accent.purple)(bold(` ${ADK_LOGO_LINE2}`))}`)
  ]);
  return router(renderer, scope, index, (i, viewScope) => {
    if (i >= keys.length) {
      if (!saveStarted) {
        saveStarted = true;
        saveAll();
      }
      return box(renderer, { paddingX: 2, paddingY: 1 }, [
        text(renderer, t`${fg(theme.text.dim)("Saving configuration...")}`)
      ]);
    }
    const currentKey = keys[i];
    const fieldSchema = shape[currentKey.key];
    const children = [logoLines()];
    if (validKeys.length > 0) {
      children.push(box(renderer, { flexDirection: "column", marginTop: 1, marginBottom: 1 }, [
        text(renderer, t`${fg(theme.status.success)("\u2713 Valid configuration:")}`),
        ...validKeys.map((key) => box(renderer, { marginLeft: 2 }, [text(renderer, t`${fg(theme.status.success)(`\u2713 ${key}`)}`)]))
      ]));
    }
    children.push(box(renderer, { flexDirection: "column", marginTop: 1, marginBottom: 1 }, [
      text(renderer, t`${fg(theme.status.warning)(bold("\u26A0\uFE0F Configuration Validation Failed"))}`),
      text(renderer, t`${fg(theme.text.dim)(`Environment: ${isProd ? "production" : "development"}`)}`),
      text(renderer, t`${fg(theme.text.dim)(`Location: ${isProd ? ".adk/config.prod.json" : ".adk/config.dev.json"}`)}`)
    ]));
    children.push(box(renderer, { marginBottom: 1 }, [
      text(renderer, t`${fg(theme.text.dim)("You can also set config non-interactively: ")}${fg(theme.accent.cyan)("adk config:set <key> <value>")}`)
    ]));
    children.push(box(renderer, { flexDirection: "column", marginTop: 1, marginBottom: 2 }, [
      text(renderer, t`${fg(theme.status.warning)("\u26A0 Configuration to fix:")}`),
      ...keys.map((item, idx) => {
        const marker = idx < i ? t`${fg(theme.status.success)(`\u2713 ${item.key}`)}` : idx === i ? t`${fg(theme.accent.purple)(`\u25B6 ${item.key}`)}` : t`${fg(theme.text.dim)(`\u2022 ${item.key}`)}`;
        return box(renderer, { marginLeft: 2 }, [text(renderer, marker)]);
      })
    ]));
    if (currentKey.error) {
      children.push(box(renderer, { marginBottom: 2 }, [
        text(renderer, t`${fg(theme.status.error)(`Current value is invalid: ${currentKey.error}`)}`)
      ]));
    }
    children.push(box(renderer, { marginBottom: 2 }, [
      text(renderer, t`${fg(theme.text.dim)(`Progress: ${i + 1}/${keys.length}`)}`)
    ]));
    const desc = currentKey.description ? ` (${currentKey.description})` : "";
    children.push(userInput(renderer, viewScope, {
      prompt: `${currentKey.key}${desc}:`,
      validate: (raw) => {
        const trimmed = raw.trim();
        if (!trimmed)
          return "Value cannot be empty";
        const coerced = coerceConfigValue(trimmed, fieldSchema);
        const result = fieldSchema.safeParse(coerced);
        return result.success ? null : result.error.issues[0]?.message || "Invalid value";
      },
      onSubmit: (raw) => {
        const coerced = coerceConfigValue(raw.trim(), fieldSchema);
        const result = fieldSchema.safeParse(coerced);
        if (result.success) {
          pendingValues[currentKey.key] = result.data;
          index.set(index() + 1);
        }
      }
    }));
    return box(renderer, { flexDirection: "column", paddingX: 2, paddingY: 2 }, children);
  });
}
async function promptForAllConfigValues(options) {
  if (options.keys.length === 0)
    return;
  return new Promise((resolve, reject) => {
    let appRef = null;
    const finish = (cb) => {
      setTimeout(() => {
        appRef?.unmount();
        cb();
      }, 80);
    };
    mount((renderer, scope) => configPromptModal(renderer, scope, {
      ...options,
      onComplete: () => finish(resolve),
      onError: (error) => finish(() => reject(error))
    }), { exitOnCtrlC: true }).then((app) => {
      appRef = app;
    });
  });
}
async function getDeploymentConfig(projectPath, isProd, options = {}) {
  const project = options.project ?? await AgentProject.load(projectPath);
  const botId = isProd ? project.agentInfo?.botId : project.agentInfo?.devId;
  if (!botId) {
    return {};
  }
  const { credentials } = await resolveConfigContext({
    projectPath,
    isProd,
    project,
    credentials: options.credentials
  });
  const configManager = new ConfigManager(botId, {
    project,
    credentials
  });
  return await configManager.getAll();
}

export { validateRemoteConfig, validateAndPromptConfig, getDeploymentConfig };
