import { readFileSync, writeFileSync, mkdirSync, chmodSync } from 'fs';
import { resolve } from 'path';
import { homedir } from 'os';

export type GoogleService = 'gmail' | 'gcal' | 'gdocs' | 'gdrive' | 'gtasks';

const AUTH_DIR = resolve(homedir(), '.config/flynn');
const AUTH_FILE = resolve(AUTH_DIR, 'auth.json');

export interface GoogleTokenRecord {
  token: Record<string, unknown>;
  scopes?: string[];
  token_file?: string;
  credentials_file?: string;
  updated_at: string;
}

export interface GoogleAuthInfo {
  services: Partial<Record<GoogleService, GoogleTokenRecord>>;
}

interface AuthStore {
  google?: GoogleAuthInfo;
  [key: string]: unknown;
}

function isIgnorableStoreError(error: unknown): boolean {
  if (!(error instanceof Error) || !('code' in error)) {
    return false;
  }
  const code = (error as NodeJS.ErrnoException).code;
  return code === 'EACCES' || code === 'EPERM' || code === 'EROFS';
}

function safeJsonParse<T>(raw: string): T | null {
  try {
    return JSON.parse(raw) as T;
  } catch {
    return null;
  }
}

function readAuthStore(): AuthStore {
  try {
    const raw = readFileSync(AUTH_FILE, 'utf-8');
    const parsed = safeJsonParse<AuthStore>(raw);
    return parsed ?? {};
  } catch {
    return {};
  }
}

function writeAuthStore(store: AuthStore): void {
  mkdirSync(AUTH_DIR, { recursive: true });
  writeFileSync(AUTH_FILE, JSON.stringify(store, null, 2) + '\n', 'utf-8');
  chmodSync(AUTH_FILE, 0o600);
}

function parseScopes(token: Record<string, unknown>, explicitScopes?: string[]): string[] | undefined {
  if (explicitScopes && explicitScopes.length > 0) {
    return explicitScopes;
  }
  const scopeValue = token.scope;
  if (typeof scopeValue !== 'string' || scopeValue.trim().length === 0) {
    return undefined;
  }
  return scopeValue.split(/\s+/).filter(Boolean);
}

function ensureGoogleAuth(store: AuthStore): GoogleAuthInfo {
  if (!store.google) {
    store.google = { services: {} };
    return store.google;
  }
  if (!store.google.services) {
    store.google.services = {};
  }
  return store.google;
}

export function loadStoredGoogleTokenRecord(service: GoogleService): GoogleTokenRecord | null {
  const store = readAuthStore();
  return store.google?.services?.[service] ?? null;
}

export function loadStoredGoogleToken(service: GoogleService): Record<string, unknown> | null {
  return loadStoredGoogleTokenRecord(service)?.token ?? null;
}

export function storeGoogleToken(
  service: GoogleService,
  token: Record<string, unknown>,
  options?: {
    scopes?: string[];
    tokenFile?: string;
    credentialsFile?: string;
  },
): void {
  const store = readAuthStore();
  const google = ensureGoogleAuth(store);
  google.services[service] = {
    token,
    scopes: parseScopes(token, options?.scopes),
    token_file: options?.tokenFile,
    credentials_file: options?.credentialsFile,
    updated_at: new Date().toISOString(),
  };
  try {
    writeAuthStore(store);
  } catch (error) {
    // Preserve legacy token-file behavior when central store cannot be written.
    if (!isIgnorableStoreError(error)) {
      throw error;
    }
  }
}

export function clearGoogleToken(service: GoogleService): void {
  const store = readAuthStore();
  if (!store.google?.services?.[service]) {
    return;
  }

  delete store.google.services[service];

  if (Object.keys(store.google.services).length === 0) {
    delete store.google;
  }
  try {
    writeAuthStore(store);
  } catch (error) {
    if (!isIgnorableStoreError(error)) {
      throw error;
    }
  }
}
