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

export const runtime = "edge";

type LaboratorioDocument = {
  $id: string;
  nome: string;
  descricao?: string;
  cnpj?: string;
  telefone?: string;
  email?: string;
  [key: string]: unknown;
};

type AppwriteConfig = {
  endpoint?: string;
  projectId?: string;
  databaseId?: string;
  collectionId?: string;
  apiKey?: string;
};

const FALLBACK_LABS: LaboratorioDocument[] = [
  {
    $id: "lab-fallback-ems",
    nome: "Laboratorio EMS",
    descricao: "Entrada de demonstracao",
    cnpj: "00.000.000/0001-00",
    telefone: "(11) 0000-0000",
    email: "contato@ems.com",
  },
  {
    $id: "lab-fallback-eurofarma",
    nome: "Laboratorio Eurofarma",
    descricao: "Entrada de demonstracao",
    cnpj: "11.111.111/0001-11",
    telefone: "(11) 1111-1111",
    email: "suporte@eurofarma.com",
  },
];

function readAppwriteConfig(): AppwriteConfig {
  return {
    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,
    collectionId:
      process.env.APPWRITE_COLLECTION_LABORATORIOS_ID ||
      process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_LABORATORIOS_ID,
    apiKey: process.env.APPWRITE_API_KEY,
  };
}

function respondWithFallbackList(
  reason: string,
  params?: { term?: string; limit: number; page: number }
) {
  const { term, limit, page } = params ?? { limit: FALLBACK_LABS.length, page: 1 };
  const normalizedTerm = term?.toLowerCase().trim();

  const filtered = normalizedTerm
    ? FALLBACK_LABS.filter((lab) =>
        lab.nome.toLowerCase().includes(normalizedTerm) ||
        lab.descricao?.toLowerCase().includes(normalizedTerm ?? "")
      )
    : [...FALLBACK_LABS];

  const safeLimit = Math.max(1, limit || 10);
  const start = (Math.max(1, page) - 1) * safeLimit;
  const documents = filtered.slice(start, start + safeLimit);

  console.warn("[API][laboratorios] Respondendo com fallback:", reason);

  return NextResponse.json(
    {
      success: true,
      documents,
      total: filtered.length,
      fallback: true,
      source: "laboratorios-fallback",
      error: reason,
    },
    { status: 200 }
  );
}

function respondWithFallbackCreate(
  nome: string,
  extras: Partial<LaboratorioDocument>,
  reason: string
) {
  const documento: LaboratorioDocument = {
    $id: `lab-fallback-${Date.now()}`,
    nome,
    ...extras,
  };

  console.warn("[API][laboratorios] Criando laboratorio em modo fallback:", reason);

  return NextResponse.json(
    {
      success: true,
      sucesso: true,
      data: documento,
      fallback: true,
      source: "laboratorios-fallback",
      mensagem: "Laboratorio criado no modo fallback",
      error: reason,
    },
    { status: 200 }
  );
}

function ensureConfig(config: AppwriteConfig) {
  const missing = Object.entries(config)
    .filter(([_, value]) => !value)
    .map(([key]) => key);

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

type ResolvedAppwriteConfig = {
  endpoint: string;
  projectId: string;
  databaseId: string;
  collectionId: string;
  apiKey: string;
};

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

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

function escapeQueryValue(value: string) {
  return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
}

function buildQueries(term: string, limit: number, offset: number) {
  const queries = [`limit(${limit})`, `offset(${offset})`];
  if (term) {
    queries.unshift(`search("nome", "${escapeQueryValue(term)}")`);
  }
  return queries;
}

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;
}

async function appwriteListDocuments(
  config: ResolvedAppwriteConfig,
  queries: string[]
): Promise<{ documents: LaboratorioDocument[]; total: number }> {
  const endpoint = normalizeEndpoint(config.endpoint);
  const url = new URL(
    `${endpoint}/databases/${config.databaseId}/collections/${config.collectionId}/documents`
  );
  for (const query of queries) {
    url.searchParams.append("queries[]", query);
  }

  const response = await fetch(url.toString(), {
    method: "GET",
    headers: buildAppwriteHeaders(config),
  });

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

  return (await response.json()) as { documents: LaboratorioDocument[]; total: number };
}

async function appwriteCreateDocument(
  config: ResolvedAppwriteConfig,
  data: Record<string, unknown>
): Promise<LaboratorioDocument> {
  const endpoint = normalizeEndpoint(config.endpoint);
  const url = `${endpoint}/databases/${config.databaseId}/collections/${config.collectionId}/documents`;

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

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

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

export async function GET(request: NextRequest) {
  console.log("[API][laboratorios] Listando laboratorios...");

  const { searchParams } = new URL(request.url);
  const limitParam = Number(searchParams.get("limit"));
  const pageParam = Number(searchParams.get("page"));
  const term = (searchParams.get("termoBuscado") || "").trim();

  const safeLimit = Number.isFinite(limitParam) && limitParam > 0 ? Math.min(limitParam, 100) : 10;
  const safePage = Number.isFinite(pageParam) && pageParam > 0 ? pageParam : 1;

  try {
    const config = readAppwriteConfig();
    const { ok, missing } = ensureConfig(config);

    if (!config.apiKey || !ok) {
      const reason = !config.apiKey
        ? "APPWRITE_API_KEY ausente"
        : `Variaveis Appwrite ausentes: ${missing.join(", ")}`;
      return respondWithFallbackList(reason, { term, limit: safeLimit, page: safePage });
    }

    const resolved: ResolvedAppwriteConfig = {
      endpoint: config.endpoint as string,
      projectId: config.projectId as string,
      databaseId: config.databaseId as string,
      collectionId: config.collectionId as string,
      apiKey: config.apiKey as string,
    };

    const offset = (Math.max(1, safePage) - 1) * safeLimit;
    const queries = buildQueries(term, safeLimit, offset);

    const response = await appwriteListDocuments(resolved, queries);

    console.log(`[API][laboratorios] ${response.total} laboratorios carregados.`);

    return NextResponse.json({
      success: true,
      documents: response.documents,
      total: response.total,
    });
  } catch (error) {
    console.error("[API][laboratorios] Erro ao listar laboratorios:", error);
    const reason = error instanceof Error ? error.message : "Falha ao listar laboratorios";
    return respondWithFallbackList(reason, { term, limit: safeLimit, page: safePage });
  }
}

export async function POST(request: NextRequest) {
  console.log("[API][laboratorios] Criando laboratorio...");

  try {
    const body = await request.json();
    const nome: string | undefined =
      typeof body?.nome === "string" ? body.nome.trim() : undefined;

    if (!nome) {
      return NextResponse.json(
        { success: false, error: "Nome do laboratorio e obrigatorio" },
        { status: 400 }
      );
    }

    const config = readAppwriteConfig();
    const { ok, missing } = ensureConfig(config);

    if (!config.apiKey || !ok) {
      const reason = !config.apiKey
        ? "APPWRITE_API_KEY ausente"
        : `Variaveis Appwrite ausentes: ${missing.join(", ")}`;
      return respondWithFallbackCreate(nome, body, reason);
    }

    const resolved: ResolvedAppwriteConfig = {
      endpoint: config.endpoint as string,
      projectId: config.projectId as string,
      databaseId: config.databaseId as string,
      collectionId: config.collectionId as string,
      apiKey: config.apiKey as string,
    };

    const dadosLaboratorio: Record<string, unknown> = {
      nome,
      descricao: typeof body.descricao === "string" ? body.descricao.trim() || "" : "",
      cnpj: typeof body.cnpj === "string" ? body.cnpj.trim() || "" : "",
      telefone: typeof body.telefone === "string" ? body.telefone.trim() || "" : "",
      email: typeof body.email === "string" ? body.email.trim() || "" : "",
    };

    try {
      const novoLaboratorio = await appwriteCreateDocument(resolved, dadosLaboratorio);

      console.log("[API][laboratorios] Laboratorio criado com sucesso");
      return NextResponse.json({
        success: true,
        sucesso: true,
        data: novoLaboratorio,
        mensagem: "Laboratorio criado com sucesso",
      });
    } catch (createError) {
      console.warn(
        "[API][laboratorios] Falha na primeira tentativa, tentando modo simplificado:",
        createError
      );

      try {
        const novoLaboratorio = await appwriteCreateDocument(resolved, { nome });

        console.log(
          "[API][laboratorios] Laboratorio criado com sucesso (modo simplificado)"
        );
        return NextResponse.json({
          success: true,
          sucesso: true,
          data: novoLaboratorio,
          mensagem: "Laboratorio criado com sucesso (modo simplificado)",
        });
      } catch (secondError) {
        console.error("[API][laboratorios] Segunda tentativa falhou:", secondError);
        const reason =
          secondError instanceof Error
            ? secondError.message
            : "Falha ao criar laboratorio";
        return respondWithFallbackCreate(nome, dadosLaboratorio, reason);
      }
    }
  } catch (error) {
    console.error("[API][laboratorios] Erro inesperado na criacao:", error);

    if (error instanceof Error && (error as any)?.status) {
      const details = (error as any).payload;
      const statusCode =
        typeof (error as any).status === "number" &&
        (error as any).status >= 400 &&
        (error as any).status < 600
          ? (error as any).status
          : 500;

      return NextResponse.json(
        {
          success: false,
          error: `Erro do Appwrite: ${error.message}`,
          details,
        },
        { status: statusCode }
      );
    }

    const reason = error instanceof Error ? error.message : "Falha na criacao";
    return NextResponse.json({ success: false, error: reason }, { status: 500 });
  }
}
