import type { Clarizen, EntityDescription } from "@arco/clarizen-lib";
import { ClarizenApiError } from "@arco/clarizen-lib";
import { isCancel, select, text } from "@clack/prompts";
import type { EntityFilter } from "./filter.js";
import { buildWhereCondition } from "./filter.js";
import { detectStateFilterCapability } from "./state-field.js";
import { resolveDisplayField } from "./resolve-display-field.js";

const BLOCKED_CZQL = /\b(DROP|DELETE|UPDATE|INSERT|ALTER|TRUNCATE)\b/i;

function validateWhereSyntax(whereClause: string): string | undefined {
  const trimmed = whereClause.trim();
  if (!trimmed) return "A cláusula WHERE não pode ser vazia.";
  if (trimmed.includes(";")) return "Não use ponto e vírgula na cláusula WHERE.";
  if (BLOCKED_CZQL.test(trimmed)) {
    return "A cláusula WHERE não pode conter comandos de modificação.";
  }
  return undefined;
}

async function validateWhereAgainstApi(
  clarizen: Clarizen,
  typeName: string,
  entityMeta: EntityDescription,
  whereClause: string,
): Promise<string | undefined> {
  const where = buildWhereCondition({ kind: "czql", whereClause });
  const displayField = resolveDisplayField(entityMeta);

  try {
    await clarizen.data.entityQuery({
      typeName,
      fields: [displayField],
      where,
      paging: { limit: 1, from: 0 },
    });
    return undefined;
  } catch (err) {
    if (err instanceof ClarizenApiError) {
      return err.message;
    }
    return err instanceof Error ? err.message : "Cláusula WHERE inválida.";
  }
}

async function promptCzqlWhere(
  clarizen: Clarizen,
  typeName: string,
  entityMeta: EntityDescription,
): Promise<EntityFilter | symbol> {
  const displayField = resolveDisplayField(entityMeta);

  console.log(`
Exemplo: State = 'Active' AND Name LIKE 'Projeto%'
O app aplicará: SELECT ${displayField} FROM ${typeName} WHERE <sua cláusula>
`);

  while (true) {
    const whereClause = await text({
      message: "Informe a cláusula WHERE (CZQL)",
      validate: validateWhereSyntax,
    });
    if (isCancel(whereClause)) return whereClause;

    const apiError = await validateWhereAgainstApi(
      clarizen,
      typeName,
      entityMeta,
      whereClause.trim(),
    );
    if (apiError) {
      console.error(`\n  Erro: ${apiError}\n`);
      continue;
    }

    return { kind: "czql", whereClause: whereClause.trim() };
  }
}

async function promptStateFilter(
  capability: NonNullable<ReturnType<typeof detectStateFilterCapability>>,
): Promise<EntityFilter | symbol> {
  const selected = await select({
    message: `Escolha o State (${capability.fieldName})`,
    options: capability.states.map((s) => ({
      value: s.value,
      label: s.label,
    })),
  });
  if (isCancel(selected)) return selected;

  const match = capability.states.find((s) => s.value === selected);
  return {
    kind: "state",
    fieldName: capability.fieldName,
    stateValue: selected,
    stateLabel: match?.label ?? selected,
  };
}

export async function promptEntityFilter(
  clarizen: Clarizen,
  typeName: string,
  entityMeta: EntityDescription,
): Promise<EntityFilter | symbol> {
  const stateCapability = detectStateFilterCapability(entityMeta);

  const options: Array<{ value: string; label: string }> = [
    { value: "all", label: "Todos os objetos" },
  ];

  if (stateCapability) {
    options.push({
      value: "state",
      label: `Filtrar por State (${stateCapability.fieldName})`,
    });
  }

  options.push({
    value: "czql",
    label: "Filtro customizado (CZQL WHERE)",
  });

  const mode = await select({
    message: "Como deseja filtrar os objetos?",
    options,
  });
  if (isCancel(mode)) return mode;

  switch (mode) {
    case "all":
      return { kind: "all" };
    case "state":
      if (!stateCapability) {
        throw new Error("Este tipo não possui filtro por State.");
      }
      return promptStateFilter(stateCapability);
    case "czql":
      return promptCzqlWhere(clarizen, typeName, entityMeta);
    default:
      return { kind: "all" };
  }
}
