import * as DocumentPicker from "expo-document-picker";
import * as LegacyFileSystem from "expo-file-system/legacy";
import type { CodexAuth } from "@/types/codex";

function sanitizeFileName(name: string): string {
  return name.replace(/[^a-zA-Z0-9._-]/g, "_");
}

async function readPickedTextFile(uri: string, fileName?: string): Promise<string> {
  try {
    const response = await fetch(uri);
    if (!response.ok) {
      throw new Error(`HTTP_ERROR_${response.status}`);
    }
    return await response.text();
  } catch {
    try {
      return await LegacyFileSystem.readAsStringAsync(uri);
    } catch {
      const cacheDirectory = LegacyFileSystem.cacheDirectory;
      if (!cacheDirectory) {
        throw new Error("DOCUMENT_NOT_READABLE");
      }

      const destination = `${cacheDirectory}${Date.now()}-${sanitizeFileName(
        fileName ?? "import.json"
      )}`;

      try {
        await LegacyFileSystem.copyAsync({ from: uri, to: destination });
        return await LegacyFileSystem.readAsStringAsync(destination);
      } catch {
        throw new Error("DOCUMENT_NOT_READABLE");
      }
    }
  }
}

export async function pickAndReadCodexAuth(): Promise<CodexAuth> {
  const result = await DocumentPicker.getDocumentAsync({
    type: "application/json",
    copyToCacheDirectory: true,
  });

  if (result.canceled) throw new Error("PICKER_CANCELLED");

  const { uri, name } = result.assets[0];
  const text = await readPickedTextFile(uri, name);

  let parsed: Record<string, unknown>;
  try {
    parsed = JSON.parse(text);
  } catch {
    throw new Error("INVALID_JSON");
  }

  const tokens = parsed["tokens"] as Record<string, unknown> | undefined;
  const accessToken = (tokens?.["access_token"] ?? parsed["accessToken"]) as string | undefined;
  const accountId = (
    tokens?.["account_id"] ??
    parsed["accountId"] ??
    parsed["account_id"]
  ) as string | undefined;

  if (!accessToken || typeof accessToken !== "string") {
    throw new Error("MISSING_ACCESS_TOKEN");
  }

  return { accessToken, accountId };
}
