import { NextRequest, NextResponse } from "next/server";

export const runtime = "edge";

type Step = 1 | 2 | 3;

type BasePayload = {
  etapa?: number;
  codigoBarras?: string;
  empresaId?: string;
  referenciaCatalogoId?: string;
  referenciaVendaId?: string;
  catalogoExistente?: boolean;
  [key: string]: unknown;
};

type StepOnePayload = BasePayload & {
  codigo_ean?: string;
  codigo_interno?: string;
  nome?: string;
  descricao?: string;
  preco_base?: number;
  laboratorio?: string;
  categoria?: string;
  subcategoria?: string;
};

type StepTwoPayload = BasePayload & {
  catalogo_id?: string;
  data_validade?: string;
  preco_venda?: number;
  observacoes?: string;
};

type StepThreePayload = BasePayload & {
  catalogo_id?: string;
  venda_id?: string;
  quantidade?: number;
};

type AppwriteConfig = {
  endpoint?: string;
  projectId?: string;
  databaseId?: string;
  apiKey?: string;
  catalogoCollectionId?: string;
  vendaCollectionId?: string;
  estoqueCollectionId?: string;
};

type CollectionKey = "catalogoCollectionId" | "vendaCollectionId" | "estoqueCollectionId";

type ResolvedBaseConfig = {
  endpoint: string;
  projectId: string;
  databaseId: string;
  apiKey: string;
};

type CreatedDocument = Record<string, unknown> & { $id: string };

const appwriteConfig: AppwriteConfig = {
  endpoint: process.env.APPWRITE_ENDPOINT || process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT,
  projectId: process.env.APPWRITE_PROJECT_ID || process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID,
  databaseId: process.env.APPWRITE_DATABASE_ID || process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID,
  apiKey: process.env.APPWRITE_API_KEY,
  catalogoCollectionId:
    process.env.APPWRITE_COLLECTION_PRODUTOS_CATALOGO_ID ||
    process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_PRODUTOS_CATALOGO_ID,
  vendaCollectionId:
    process.env.APPWRITE_COLLECTION_PRODUTOS_VENDA_ID ||
    process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_PRODUTOS_VENDA_ID,
  estoqueCollectionId:
    process.env.APPWRITE_COLLECTION_PRODUTOS_ESTOQUE_ID ||
    process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_PRODUTOS_ESTOQUE_ID,
};

function parseStep(value: unknown): Step | null {
  const numberValue = Number(value);
  if (numberValue === 1 || numberValue === 2 || numberValue === 3) {
    return numberValue;
  }
  return null;
}

function ensureConfig(requireCollections: Array<CollectionKey>) {
  const missing: string[] = [];
  if (!appwriteConfig.endpoint) missing.push("APPWRITE_ENDPOINT");
  if (!appwriteConfig.projectId) missing.push("APPWRITE_PROJECT_ID");
  if (!appwriteConfig.databaseId) missing.push("APPWRITE_DATABASE_ID");
  if (!appwriteConfig.apiKey) missing.push("APPWRITE_API_KEY");

  for (const key of requireCollections) {
    if (!appwriteConfig[key]) {
      missing.push(key);
    }
  }

  return {
    ok: missing.length === 0,
    missing,
  };
}

function normalizeEndpoint(endpoint: string) {
  return endpoint.endsWith("/") ? endpoint.slice(0, -1) : endpoint;
}

function buildAppwriteHeaders(base: ResolvedBaseConfig) {
  return {
    "X-Appwrite-Project": base.projectId,
    "X-Appwrite-Key": base.apiKey,
    Accept: "application/json",
  };
}

async function buildAppwriteError(response: Response) {
  let message = `Appwrite responded with status ${response.status}`;
  let payload: unknown;

  try {
    payload = await response.json();
    if (
      payload &&
      typeof payload === "object" &&
      "message" in payload &&
      typeof (payload as any).message === "string"
    ) {
      message = (payload as any).message;
    }
  } catch {
    // ignore json parse errors
  }

  const error = new Error(message);
  (error as any).status = response.status;
  (error as any).payload = payload;
  return error;
}

function getBaseConfig(): ResolvedBaseConfig {
  if (
    !appwriteConfig.endpoint ||
    !appwriteConfig.projectId ||
    !appwriteConfig.databaseId ||
    !appwriteConfig.apiKey
  ) {
    throw new Error("Configuracao do Appwrite incompleta");
  }

  return {
    endpoint: appwriteConfig.endpoint,
    projectId: appwriteConfig.projectId,
    databaseId: appwriteConfig.databaseId,
    apiKey: appwriteConfig.apiKey,
  };
}

async function createDocument(
  base: ResolvedBaseConfig,
  collectionId: string,
  data: Record<string, unknown>
): Promise<CreatedDocument> {
  const endpoint = normalizeEndpoint(base.endpoint);
  const url = `${endpoint}/databases/${base.databaseId}/collections/${collectionId}/documents`;

  const response = await fetch(url, {
    method: "POST",
    headers: {
      ...buildAppwriteHeaders(base),
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      documentId: "unique()",
      data,
    }),
  });

  if (!response.ok) {
    throw await buildAppwriteError(response);
  }

  return (await response.json()) as CreatedDocument;
}

async function searchProductByBarcode(
  base: ResolvedBaseConfig,
  collectionId: string,
  codigoBarras: string
): Promise<CreatedDocument | null> {
  const endpoint = normalizeEndpoint(base.endpoint);
  const url = `${endpoint}/databases/${base.databaseId}/collections/${collectionId}/documents`;

  try {
    const response = await fetch(url, {
      method: "GET",
      headers: buildAppwriteHeaders(base),
    });

    if (!response.ok) {
      console.error("Erro ao buscar produto por código de barras:", await response.text());
      return null;
    }

    const result = await response.json();
    const documents = result.documents || [];
    
    // Buscar produto com código de barras correspondente
    const produto = documents.find((doc: any) => 
      doc.codigo_ean === codigoBarras || doc.codigo_interno === codigoBarras
    );

    return produto || null;
  } catch (error) {
    console.error("Erro na busca por código de barras:", error);
    return null;
  }
}

function sanitizeDocument<T extends Record<string, unknown>>(data: T) {
  const document: Record<string, unknown> = {};
  Object.entries(data).forEach(([key, value]) => {
    if (value === undefined) {
      return;
    }

    if (typeof value === "string") {
      const trimmed = value.trim();
      if (trimmed.length === 0) {
        return;
      }
      document[key] = trimmed;
      return;
    }

    document[key] = value;
  });

  return document;
}

function toNumber(value: unknown) {
  if (typeof value === "number") return value;
  if (typeof value === "string" && value.trim().length > 0) {
    const parsed = Number(value.replace(",", "."));
    return Number.isFinite(parsed) ? parsed : NaN;
  }
  return NaN;
}

function fallbackResponse(step: Step, reason: string, extra: Record<string, unknown>) {
  const base = {
    success: true,
    fallback: true,
    etapa: step,
    reason,
    message: "Cadastro processado em modo fallback (dados nao enviados ao Appwrite)",
    data: extra,
  };

  switch (step) {
    case 1: {
      return NextResponse.json({
        ...base,
        catalogoId: extra.catalogoId,
        catalogo: extra.catalogo,
      });
    }
    case 2: {
      return NextResponse.json({
        ...base,
        vendaId: extra.vendaId,
        produtoVenda: extra.venda,
      });
    }
    case 3: {
      return NextResponse.json({
        ...base,
        estoqueId: extra.estoqueId,
        produtoEstoque: extra.estoque,
      });
    }
    default:
      return NextResponse.json(base);
  }
}

function buildFallbackCatalogo(payload: StepOnePayload) {
  const fallbackId = `catalogo-fallback-${Date.now()}`;
  const preco = toNumber(payload.preco_base);

  const catalogo = {
    $id: fallbackId,
    codigo_ean: String(payload.codigo_ean ?? ""),
    codigo_interno: String(payload.codigo_interno ?? payload.codigo_ean ?? ""),
    nome: String(payload.nome ?? "Produto sem nome"),
    descricao: String(payload.descricao ?? ""),
    preco_base: Number.isFinite(preco) ? preco : 0,
    laboratorio: String(payload.laboratorio ?? ""),
    categoria: String(payload.categoria ?? ""),
    subcategoria: String(payload.subcategoria ?? ""),
    fallback: true,
    createdAt: new Date().toISOString(),
  };

  return {
    catalogoId: fallbackId,
    catalogo,
  };
}

function buildFallbackVenda(payload: StepTwoPayload) {
  const fallbackId = `venda-fallback-${Date.now()}`;
  const precoVenda = toNumber(payload.preco_venda);

  const venda = {
    $id: fallbackId,
    catalogo_id: String(payload.catalogo_id ?? ""),
    data_validade: String(payload.data_validade ?? ""),
    preco_venda: Number.isFinite(precoVenda) ? precoVenda : 0,
    observacoes: String(payload.observacoes ?? ""),
    fallback: true,
    createdAt: new Date().toISOString(),
  };

  return {
    vendaId: fallbackId,
    venda,
  };
}

function buildFallbackEstoque(payload: StepThreePayload) {
  const fallbackId = `estoque-fallback-${Date.now()}`;
  const quantidadeNumero = toNumber(payload.quantidade);

  const estoque = {
    $id: fallbackId,
    catalogo_id: String(payload.catalogo_id ?? ""),
    venda_id: String(payload.venda_id ?? ""),
    quantidade: Number.isFinite(quantidadeNumero) ? quantidadeNumero : 0,
    fallback: true,
    createdAt: new Date().toISOString(),
  };

  return {
    estoqueId: fallbackId,
    estoque,
  };
}

async function handleStepOne(payload: StepOnePayload) {
  // Validações dos campos obrigatórios
  if (!payload.codigo_ean || typeof payload.codigo_ean !== "string") {
    return NextResponse.json(
      { success: false, error: "Campo codigo_ean obrigatorio" },
      { status: 400 }
    );
  }

  if (!payload.nome || typeof payload.nome !== "string") {
    return NextResponse.json(
      { success: false, error: "Campo nome obrigatorio" },
      { status: 400 }
    );
  }

  const precoNormalizado = toNumber(payload.preco_base);
  if (!Number.isFinite(precoNormalizado)) {
    return NextResponse.json(
      { success: false, error: "Campo preco_base obrigatorio e deve ser um numero valido" },
      { status: 400 }
    );
  }

  if (!payload.laboratorio || typeof payload.laboratorio !== "string") {
    return NextResponse.json(
      { success: false, error: "Campo laboratorio obrigatorio (apenas o ID)" },
      { status: 400 }
    );
  }

  if (!payload.categoria || typeof payload.categoria !== "string") {
    return NextResponse.json(
      { success: false, error: "Campo categoria obrigatorio (apenas o ID)" },
      { status: 400 }
    );
  }

  const { ok, missing } = ensureConfig(["catalogoCollectionId"]);
  if (!ok) {
    const fallback = buildFallbackCatalogo(payload);
    const reason = `Variaveis Appwrite ausentes: ${missing.join(", ")}`;
    return fallbackResponse(1, reason, {
      ...fallback,
      payload,
    });
  }

  try {
    const baseConfig = getBaseConfig();
    const collectionId = appwriteConfig.catalogoCollectionId as string;

    const documentData = sanitizeDocument({
      codigo_ean: payload.codigo_ean,
      codigo_interno: payload.codigo_interno || payload.codigo_ean, // Se não informado, usa o EAN
      nome: payload.nome,
      descricao: payload.descricao || undefined,
      preco_base: precoNormalizado,
      laboratorio: payload.laboratorio, // Apenas o ID
      categoria: payload.categoria, // Apenas o ID
      subcategoria: payload.subcategoria || undefined, // Opcional
    });

    const novoCatalogo = await createDocument(baseConfig, collectionId, documentData);

    return NextResponse.json({
      success: true,
      etapa: 1,
      catalogoId: novoCatalogo.$id,
      catalogo: novoCatalogo,
    });
  } catch (error) {
    console.error("[cadastro-produto][etapa-1] Erro ao criar documento", error);
    const fallback = buildFallbackCatalogo(payload);
    const reason =
      error instanceof Error ? error.message : "Falha ao criar documento do catalogo";
    return fallbackResponse(1, reason, {
      ...fallback,
      payload,
      error: error instanceof Error ? error.message : "Erro desconhecido",
      details: error,
    });
  }
}

async function handleStepTwo(payload: StepTwoPayload) {
  // Validações dos campos obrigatórios
  if (!payload.catalogo_id || typeof payload.catalogo_id !== "string") {
    return NextResponse.json(
      { success: false, error: "Campo catalogo_id obrigatorio (ID do produto da etapa 1)" },
      { status: 400 }
    );
  }

  if (!payload.data_validade || typeof payload.data_validade !== "string") {
    return NextResponse.json(
      { success: false, error: "Campo data_validade obrigatorio" },
      { status: 400 }
    );
  }

  const precoNormalizado = toNumber(payload.preco_venda);
  if (!Number.isFinite(precoNormalizado)) {
    return NextResponse.json(
      { success: false, error: "Campo preco_venda obrigatorio e deve ser um numero valido" },
      { status: 400 }
    );
  }

  const { ok, missing } = ensureConfig(["vendaCollectionId"]);
  if (!ok) {
    const fallback = buildFallbackVenda(payload);
    const reason = `Variaveis Appwrite ausentes: ${missing.join(", ")}`;
    return fallbackResponse(2, reason, {
      ...fallback,
      payload,
    });
  }

  try {
    const baseConfig = getBaseConfig();
    const collectionId = appwriteConfig.vendaCollectionId as string;

    const documentData = sanitizeDocument({
      catalogo_id: payload.catalogo_id, // ID do produto da etapa 1
      data_validade: payload.data_validade,
      preco_venda: precoNormalizado,
      observacoes: payload.observacoes || undefined, // Campo opcional
    });

    const novaVenda = await createDocument(baseConfig, collectionId, documentData);

    return NextResponse.json({
      success: true,
      etapa: 2,
      vendaId: novaVenda.$id,
      venda: novaVenda,
    });
  } catch (error) {
    console.error("[cadastro-produto][etapa-2] Erro ao criar documento", error);
    const fallback = buildFallbackVenda(payload);
    const reason =
      error instanceof Error ? error.message : "Falha ao criar documento de venda";
    return fallbackResponse(2, reason, {
      ...fallback,
      payload,
      error: error instanceof Error ? error.message : "Erro desconhecido",
      details: error,
    });
  }
}

async function handleStepThree(payload: StepThreePayload) {
  // Validações dos campos obrigatórios
  if (!payload.catalogo_id || typeof payload.catalogo_id !== "string") {
    return NextResponse.json(
      { success: false, error: "Campo catalogo_id obrigatorio (ID do produto da etapa 1)" },
      { status: 400 }
    );
  }

  if (!payload.venda_id || typeof payload.venda_id !== "string") {
    return NextResponse.json(
      { success: false, error: "Campo venda_id obrigatorio (ID do produto da etapa 2)" },
      { status: 400 }
    );
  }

  const quantidadeNormalizada = toNumber(payload.quantidade);
  if (!Number.isFinite(quantidadeNormalizada)) {
    return NextResponse.json(
      { success: false, error: "Campo quantidade obrigatorio e deve ser um numero valido" },
      { status: 400 }
    );
  }

  const { ok, missing } = ensureConfig(["estoqueCollectionId"]);
  if (!ok) {
    const fallback = buildFallbackEstoque(payload);
    const reason = `Variaveis Appwrite ausentes: ${missing.join(", ")}`;
    return fallbackResponse(3, reason, {
      ...fallback,
      payload,
    });
  }

  try {
    const baseConfig = getBaseConfig();
    const collectionId = appwriteConfig.estoqueCollectionId as string;

    const documentData = sanitizeDocument({
      catalogo_id: payload.catalogo_id, // ID do produto da etapa 1
      venda_id: payload.venda_id, // ID do produto da etapa 2
      quantidade: quantidadeNormalizada,
    });

    const novoEstoque = await createDocument(baseConfig, collectionId, documentData);

    return NextResponse.json({
      success: true,
      etapa: 3,
      estoqueId: novoEstoque.$id,
      estoque: novoEstoque,
    });
  } catch (error) {
    console.error("[cadastro-produto][etapa-3] Erro ao criar documento", error);
    const fallback = buildFallbackEstoque(payload);
    const reason =
      error instanceof Error ? error.message : "Falha ao criar documento de estoque";
    return fallbackResponse(3, reason, {
      ...fallback,
      payload,
      error: error instanceof Error ? error.message : "Erro desconhecido",
      details: error,
    });
  }
}

export async function POST(request: NextRequest) {
  let payload: BasePayload = {};

  try {
    payload = (await request.json()) as BasePayload;
  } catch (error) {
    console.error("[cadastro-produto][POST] Payload invalido", error);
    return NextResponse.json(
      { success: false, error: "Payload invalido" },
      { status: 400 }
    );
  }

  const etapa = parseStep(payload.etapa);
  if (!etapa) {
    return NextResponse.json(
      { success: false, error: "Campo etapa obrigatorio (1, 2 ou 3)" },
      { status: 400 }
    );
  }

  if (etapa === 1) {
    return handleStepOne(payload as StepOnePayload);
  }
  if (etapa === 2) {
    return handleStepTwo(payload as StepTwoPayload);
  }
  return handleStepThree(payload as StepThreePayload);
}
