/**
 * Landing Page Deployer
 * Deploys generated pages to local or Vercel
 */

import { promises as fs } from 'fs';
import * as path from 'path';
import type { GeneratedPages } from './generator';

export interface DeploymentResult {
  optInUrl: string;
  privacyPolicyUrl: string;
  termsUrl: string;
  deploymentType: 'local' | 'vercel';
  deployedAt: Date;
}

export interface LocalDeploymentOptions {
  publicDir?: string;  // Default: './public'
  baseUrl?: string;    // Default: 'http://localhost:3000'
}

export interface VercelDeploymentOptions {
  apiToken: string;
  teamId?: string;
  projectName?: string;
  subdomain?: string;  // e.g., 'comply' for comply.yourdomain.com
  customDomain?: string;
}

/**
 * Deploy to local filesystem (for Express/self-hosted)
 */
export async function deployLocal(
  pages: GeneratedPages,
  options: LocalDeploymentOptions = {}
): Promise<DeploymentResult> {
  
  const publicDir = options.publicDir || './public';
  const baseUrl = options.baseUrl || 'http://localhost:3000';
  
  // Create directories
  const slugDir = path.join(publicDir, pages.slug);
  await fs.mkdir(slugDir, { recursive: true });
  
  // Write HTML files
  await Promise.all([
    fs.writeFile(
      path.join(slugDir, 'index.html'),
      pages.optInHtml,
      'utf-8'
    ),
    fs.writeFile(
      path.join(slugDir, 'privacy-policy.html'),
      pages.privacyPolicyHtml,
      'utf-8'
    ),
    fs.writeFile(
      path.join(slugDir, 'terms.html'),
      pages.termsHtml,
      'utf-8'
    ),
  ]);
  
  console.log(`✅ Deployed locally to ${slugDir}`);
  
  return {
    optInUrl: `${baseUrl}/${pages.slug}/`,
    privacyPolicyUrl: `${baseUrl}/${pages.slug}/privacy-policy.html`,
    termsUrl: `${baseUrl}/${pages.slug}/terms.html`,
    deploymentType: 'local',
    deployedAt: new Date(),
  };
}

/**
 * Deploy to Vercel as a static site
 */
export async function deployVercel(
  pages: GeneratedPages,
  options: VercelDeploymentOptions
): Promise<DeploymentResult> {
  
  // Create temporary deployment directory
  const tempDir = path.join('/tmp', `vercel-deploy-${pages.slug}-${Date.now()}`);
  await fs.mkdir(tempDir, { recursive: true });
  
  try {
    // Write files to temp directory
    await Promise.all([
      fs.writeFile(
        path.join(tempDir, 'index.html'),
        pages.optInHtml,
        'utf-8'
      ),
      fs.writeFile(
        path.join(tempDir, 'privacy-policy.html'),
        pages.privacyPolicyHtml,
        'utf-8'
      ),
      fs.writeFile(
        path.join(tempDir, 'terms.html'),
        pages.termsHtml,
        'utf-8'
      ),
    ]);
    
    // Create vercel.json config
    const vercelConfig = {
      version: 2,
      name: options.projectName || `a2p-${pages.slug}`,
      builds: [
        {
          src: '**/*.html',
          use: '@vercel/static',
        },
      ],
      routes: [
        {
          src: '/(.*)',
          dest: '/$1',
        },
      ],
    };
    
    await fs.writeFile(
      path.join(tempDir, 'vercel.json'),
      JSON.stringify(vercelConfig, null, 2),
      'utf-8'
    );
    
    // Deploy to Vercel using their API
    const deployment = await deployToVercelAPI(tempDir, options);
    
    // Build URLs
    const baseUrl = deployment.url.startsWith('http')
      ? deployment.url
      : `https://${deployment.url}`;
    
    console.log(`✅ Deployed to Vercel: ${baseUrl}`);
    
    return {
      optInUrl: `${baseUrl}/`,
      privacyPolicyUrl: `${baseUrl}/privacy-policy.html`,
      termsUrl: `${baseUrl}/terms.html`,
      deploymentType: 'vercel',
      deployedAt: new Date(),
    };
    
  } finally {
    // Clean up temp directory
    try {
      await fs.rm(tempDir, { recursive: true, force: true });
    } catch (err) {
      console.warn(`⚠️ Failed to clean up temp directory: ${tempDir}`);
    }
  }
}

/**
 * Deploy to Vercel using their REST API
 */
async function deployToVercelAPI(
  sourceDir: string,
  options: VercelDeploymentOptions
): Promise<{ url: string; deploymentId: string }> {
  
  // Read all files and prepare for upload
  const files = await prepareFilesForVercel(sourceDir);
  
  // Prepare deployment request
  const deploymentPayload: any = {
    name: options.projectName || `a2p-landing`,
    files,
    projectSettings: {
      framework: null,
      buildCommand: null,
      outputDirectory: null,
    },
    target: 'production',
  };
  
  // Add team ID if provided
  const queryParams = options.teamId ? `?teamId=${options.teamId}` : '';
  
  // Deploy to Vercel
  const response = await fetch(`https://api.vercel.com/v13/deployments${queryParams}`, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${options.apiToken}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(deploymentPayload),
  });
  
  if (!response.ok) {
    const errorText = await response.text();
    throw new Error(`Vercel deployment failed: ${response.status} ${errorText}`);
  }
  
  const result = await response.json();
  
  // If custom domain/subdomain is provided, assign it
  if (options.customDomain || options.subdomain) {
    await assignCustomDomain(
      result.id,
      options.customDomain || `${options.subdomain}.vercel.app`,
      options
    );
  }
  
  return {
    url: result.url,
    deploymentId: result.id,
  };
}

/**
 * Prepare files for Vercel deployment (read and encode)
 */
async function prepareFilesForVercel(sourceDir: string): Promise<any[]> {
  const files: any[] = [];
  
  const entries = await fs.readdir(sourceDir, { withFileTypes: true });
  
  for (const entry of entries) {
    if (entry.isFile()) {
      const filePath = path.join(sourceDir, entry.name);
      const content = await fs.readFile(filePath, 'utf-8');
      
      files.push({
        file: entry.name,
        data: content,
        encoding: 'utf-8',
      });
    }
  }
  
  return files;
}

/**
 * Assign custom domain to Vercel deployment
 */
async function assignCustomDomain(
  deploymentId: string,
  domain: string,
  options: VercelDeploymentOptions
): Promise<void> {
  
  const queryParams = options.teamId ? `?teamId=${options.teamId}` : '';
  
  const response = await fetch(`https://api.vercel.com/v9/projects/${options.projectName}/domains${queryParams}`, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${options.apiToken}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      name: domain,
    }),
  });
  
  if (!response.ok) {
    console.warn(`⚠️ Failed to assign custom domain: ${domain}`);
  } else {
    console.log(`✅ Assigned custom domain: ${domain}`);
  }
}

/**
 * Main deployment function - auto-selects deployment type
 */
export async function deploy(
  pages: GeneratedPages,
  type: 'local' | 'vercel',
  options: LocalDeploymentOptions | VercelDeploymentOptions
): Promise<DeploymentResult> {
  
  if (type === 'local') {
    return deployLocal(pages, options as LocalDeploymentOptions);
  } else {
    return deployVercel(pages, options as VercelDeploymentOptions);
  }
}

/**
 * Deploy and update submission record with URLs
 */
export async function deployAndUpdateRecord(
  pages: GeneratedPages,
  type: 'local' | 'vercel',
  options: LocalDeploymentOptions | VercelDeploymentOptions,
  submissionId: string,
  updateFn: (id: string, urls: { 
    landingPageUrl: string; 
    privacyPolicyUrl: string; 
    termsUrl: string;
  }) => Promise<void>
): Promise<DeploymentResult> {
  
  const result = await deploy(pages, type, options);
  
  // Update submission record with URLs
  await updateFn(submissionId, {
    landingPageUrl: result.optInUrl,
    privacyPolicyUrl: result.privacyPolicyUrl,
    termsUrl: result.termsUrl,
  });
  
  return result;
}
