/**
 * TextNow Authentication Module
 * Handles cookie-based authentication, CSRF tokens, and credential storage
 */

import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
import { homedir } from 'node:os';
import { join } from 'node:path';

// ============================================================================
// Types
// ============================================================================

export interface TextNowCredentials {
  username: string;
  cookies: string;
  csrfToken: string;
  savedAt: string;
}

export interface ParsedCookies {
  connectSid?: string;
  csrf?: string;
  xsrfToken?: string;
  raw: string;
}

export class TextNowAuthError extends Error {
  constructor(
    message: string,
    public code: string,
    public statusCode?: number
  ) {
    super(message);
    this.name = 'TextNowAuthError';
  }
}

// ============================================================================
// Constants
// ============================================================================

const CREDENTIALS_DIR = join(homedir(), '.textnow');
const CREDENTIALS_FILE = join(CREDENTIALS_DIR, 'credentials.json');

// ============================================================================
// Cookie Parsing
// ============================================================================

/**
 * Parse a cookie string into its components
 * Extracts connect.sid, _csrf, and XSRF-TOKEN
 */
export function parseCookies(cookieString: string): ParsedCookies {
  const cookies: ParsedCookies = { raw: cookieString };
  
  // Parse individual cookies
  const pairs = cookieString.split(';').map(s => s.trim());
  
  for (const pair of pairs) {
    const [name, ...valueParts] = pair.split('=');
    const value = valueParts.join('='); // Handle values with = in them
    
    if (!name || !value) continue;
    
    const trimmedName = name.trim();
    const trimmedValue = value.trim();
    
    switch (trimmedName) {
      case 'connect.sid':
        cookies.connectSid = trimmedValue;
        break;
      case '_csrf':
        cookies.csrf = trimmedValue;
        break;
      case 'XSRF-TOKEN':
        cookies.xsrfToken = trimmedValue;
        break;
    }
  }
  
  return cookies;
}

/**
 * Extract the CSRF token value from cookies
 * IMPORTANT: Use XSRF-TOKEN value (NOT _csrf) for the X-CSRF-Token header
 */
export function extractCSRFToken(cookieString: string): string | null {
  const parsed = parseCookies(cookieString);
  return parsed.xsrfToken || null;
}

/**
 * Validate that all required cookies are present
 */
export function validateCookies(cookies: ParsedCookies): boolean {
  return !!(cookies.connectSid && cookies.xsrfToken);
}

// ============================================================================
// Credential Storage
// ============================================================================

/**
 * Ensure the credentials directory exists
 */
function ensureCredentialsDir(): void {
  if (!existsSync(CREDENTIALS_DIR)) {
    mkdirSync(CREDENTIALS_DIR, { mode: 0o700, recursive: true });
  }
}

/**
 * Save credentials to ~/.textnow/credentials.json
 */
export function saveCredentials(
  username: string,
  cookies: string,
  csrfToken: string
): void {
  ensureCredentialsDir();
  
  const credentials: TextNowCredentials = {
    username,
    cookies,
    csrfToken,
    savedAt: new Date().toISOString(),
  };
  
  writeFileSync(CREDENTIALS_FILE, JSON.stringify(credentials, null, 2), {
    mode: 0o600, // Read/write for owner only
  });
  
  console.log(`[TextNowAuth] Credentials saved to ${CREDENTIALS_FILE}`);
}

/**
 * Load credentials from ~/.textnow/credentials.json
 */
export function loadCredentials(): TextNowCredentials | null {
  if (!existsSync(CREDENTIALS_FILE)) {
    return null;
  }
  
  try {
    const data = readFileSync(CREDENTIALS_FILE, 'utf-8');
    return JSON.parse(data) as TextNowCredentials;
  } catch (err) {
    console.error('[TextNowAuth] Failed to load credentials:', err);
    return null;
  }
}

/**
 * Check if stored credentials exist
 */
export function hasStoredCredentials(): boolean {
  return existsSync(CREDENTIALS_FILE);
}

/**
 * Delete stored credentials
 */
export function clearCredentials(): void {
  if (existsSync(CREDENTIALS_FILE)) {
    const { unlinkSync } = require('node:fs');
    unlinkSync(CREDENTIALS_FILE);
    console.log('[TextNowAuth] Credentials cleared');
  }
}

// ============================================================================
// Auth Helper Class
// ============================================================================

export class TextNowAuth {
  private username: string | null = null;
  private cookies: string | null = null;
  private csrfToken: string | null = null;

  constructor() {
    // Try to load stored credentials on init
    const stored = loadCredentials();
    if (stored) {
      this.username = stored.username;
      this.cookies = stored.cookies;
      this.csrfToken = stored.csrfToken;
    }
  }

  /**
   * Set credentials from browser cookies
   * @param username - TextNow username (for API endpoints)
   * @param cookieString - Full cookie string from browser
   * @param save - Whether to persist to disk (default: true)
   */
  setCredentials(
    username: string,
    cookieString: string,
    save: boolean = true
  ): void {
    const parsed = parseCookies(cookieString);
    
    if (!validateCookies(parsed)) {
      throw new TextNowAuthError(
        'Missing required cookies (connect.sid or XSRF-TOKEN)',
        'INVALID_COOKIES'
      );
    }
    
    this.username = username;
    this.cookies = cookieString;
    this.csrfToken = parsed.xsrfToken!;
    
    if (save) {
      saveCredentials(username, cookieString, this.csrfToken);
    }
  }

  /**
   * Get the username for API calls
   */
  getUsername(): string {
    if (!this.username) {
      throw new TextNowAuthError('Not authenticated', 'NOT_AUTHENTICATED');
    }
    return this.username;
  }

  /**
   * Get headers required for TextNow API requests
   */
  getAuthHeaders(): Record<string, string> {
    if (!this.cookies || !this.csrfToken) {
      throw new TextNowAuthError('Not authenticated', 'NOT_AUTHENTICATED');
    }
    
    return {
      'Cookie': this.cookies,
      'X-CSRF-Token': this.csrfToken,
      'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
      'X-Requested-With': 'XMLHttpRequest',
      'Referer': 'https://www.textnow.com/messaging',
      'Origin': 'https://www.textnow.com',
    };
  }

  /**
   * Check if authenticated
   */
  isAuthenticated(): boolean {
    return !!(this.username && this.cookies && this.csrfToken);
  }

  /**
   * Clear authentication state
   */
  logout(clearStored: boolean = true): void {
    this.username = null;
    this.cookies = null;
    this.csrfToken = null;
    
    if (clearStored) {
      clearCredentials();
    }
  }

  /**
   * Get the raw cookie string
   */
  getCookies(): string | null {
    return this.cookies;
  }

  /**
   * Get the CSRF token
   */
  getCSRFToken(): string | null {
    return this.csrfToken;
  }
}

export default TextNowAuth;
