#!/usr/bin/env node

import { z } from 'zod';
import { QuickBooksClient } from './clients/quickbooks.js';
import { createMCPServer, startServer } from './server.js';

/**
 * Environment variable schema
 */
const envSchema = z.object({
  QBO_ACCESS_TOKEN: z.string().min(1, 'QBO_ACCESS_TOKEN is required'),
  QBO_REALM_ID: z.string().min(1, 'QBO_REALM_ID is required'),
  QBO_REFRESH_TOKEN: z.string().optional(),
  QBO_SANDBOX: z
    .string()
    .optional()
    .transform(val => val === 'true' || val === '1'),
  QBO_MINOR_VERSION: z
    .string()
    .optional()
    .transform(val => (val ? parseInt(val, 10) : undefined)),
});

/**
 * Validate environment variables
 */
function validateEnvironment() {
  try {
    return envSchema.parse(process.env);
  } catch (error) {
    if (error instanceof z.ZodError) {
      console.error('❌ Environment validation failed:');
      error.errors.forEach(err => {
        console.error(`  - ${err.path.join('.')}: ${err.message}`);
      });
      process.exit(1);
    }
    throw error;
  }
}

/**
 * Health check endpoint (optional)
 */
function setupHealthCheck() {
  // Simple health indicator - write to stderr so it doesn't interfere with stdio transport
  const logHealth = () => {
    process.stderr.write(
      JSON.stringify({
        status: 'healthy',
        timestamp: new Date().toISOString(),
        uptime: process.uptime(),
      }) + '\n'
    );
  };

  // Log health every 5 minutes
  const healthInterval = setInterval(logHealth, 5 * 60 * 1000);

  return () => clearInterval(healthInterval);
}

/**
 * Graceful shutdown handler
 */
function setupGracefulShutdown(cleanup: () => void) {
  const shutdown = (signal: string) => {
    process.stderr.write(`\n⚠️  Received ${signal}, shutting down gracefully...\n`);
    cleanup();
    process.exit(0);
  };

  process.on('SIGTERM', () => shutdown('SIGTERM'));
  process.on('SIGINT', () => shutdown('SIGINT'));
}

/**
 * Main entry point
 */
async function main() {
  // Validate environment
  const env = validateEnvironment();

  process.stderr.write('🚀 Starting QuickBooks Online MCP Server...\n');
  process.stderr.write(`   Realm ID: ${env.QBO_REALM_ID}\n`);
  process.stderr.write(`   Sandbox: ${env.QBO_SANDBOX ? 'Yes' : 'No'}\n`);
  process.stderr.write(`   Minor Version: ${env.QBO_MINOR_VERSION || 73}\n\n`);

  // Create QuickBooks client
  const qboClient = new QuickBooksClient({
    accessToken: env.QBO_ACCESS_TOKEN,
    realmId: env.QBO_REALM_ID,
    refreshToken: env.QBO_REFRESH_TOKEN,
    sandbox: env.QBO_SANDBOX,
    minorVersion: env.QBO_MINOR_VERSION,
  });

  // Test connection
  try {
    const companyInfo = await qboClient.getCompanyInfo();
    process.stderr.write(`✅ Connected to: ${companyInfo.CompanyName}\n\n`);
  } catch (error: any) {
    process.stderr.write('❌ Failed to connect to QuickBooks Online:\n');
    process.stderr.write(`   ${error.message}\n\n`);
    process.exit(1);
  }

  // Create MCP server
  const server = createMCPServer({
    name: '@mcpengine/quickbooks',
    version: '1.0.0',
    qboClient,
  });

  // Setup health check
  const cleanupHealth = setupHealthCheck();

  // Setup graceful shutdown
  setupGracefulShutdown(() => {
    cleanupHealth();
  });

  // Start server with stdio transport
  process.stderr.write('📡 MCP Server ready (stdio transport)\n');
  process.stderr.write('   Waiting for requests...\n\n');

  await startServer(server);
}

// Handle unhandled errors
process.on('unhandledRejection', (reason, promise) => {
  process.stderr.write('❌ Unhandled Rejection:\n');
  process.stderr.write(`   ${reason}\n`);
  process.exit(1);
});

process.on('uncaughtException', (error) => {
  process.stderr.write('❌ Uncaught Exception:\n');
  process.stderr.write(`   ${error.message}\n`);
  process.stderr.write(`   ${error.stack}\n`);
  process.exit(1);
});

// Run
main().catch((error) => {
  process.stderr.write('❌ Fatal error:\n');
  process.stderr.write(`   ${error.message}\n`);
  process.exit(1);
});
