import { prisma } from './db'
import { createAuditLog } from './audit'
import fs from 'fs/promises'
import path from 'path'
import crypto from 'crypto'

const APP_ROOT = process.cwd()
const CONFIG_DIR = path.join(APP_ROOT, 'config')
const INSTALLED_FILE = path.join(CONFIG_DIR, 'installed.json')

export interface InstallationConfig {
  // General
  timezone: string
  defaultLanguage: string
  
  // Branding
  panelName: string
  logoUrl?: string
  backgroundUrl?: string
  primaryColor: string
  secondaryColor: string
  themeStyle: string
  
  // UCP Database
  dbHost: string
  dbPort: number
  dbName: string
  dbUser: string
  dbPassword: string
  
  // FiveM Game Database
  gameDbHost: string
  gameDbPort: number
  gameDbName: string
  gameDbUser: string
  gameDbPassword: string
  gameDbFramework: 'auto' | 'esx' | 'qbcore'
  
  // Discord OAuth
  discordClientId: string
  discordClientSecret: string
  discordCallbackUrl: string
  
  // Discord Webhook
  discordWebhookUrl?: string
  
  // Domain
  useDirectIp: boolean
  mainDomain?: string
  subdomain?: string
  
  // Admin
  adminDiscordId: string
  
  // Security
  jwtSecret: string
  sessionDuration: number
}

export interface InstallationState {
  isInstalled: boolean
  installedAt?: string
  version: string
  adminDiscordId?: string
}

export async function checkInstallationStatus(): Promise<InstallationState> {
  try {
    // First check environment variable (set by web installer after completion)
    if (process.env.INSTALLATION_COMPLETE === 'true') {
      return {
        isInstalled: true,
        installedAt: process.env.INSTALLATION_DATE || new Date().toISOString(),
        version: process.env.APP_VERSION || '1.0.0',
        adminDiscordId: process.env.ADMIN_DISCORD_ID,
      }
    }

    // Then check file-based flag (faster)
    try {
      const data = await fs.readFile(INSTALLED_FILE, 'utf8')
      const state = JSON.parse(data) as InstallationState
      if (state.isInstalled) {
        return state
      }
    } catch {
      // File doesn't exist or is invalid, check database
    }

    // Check database
    try {
      const dbState = await prisma.installationState.findFirst()
      if (dbState?.isInstalled) {
        // Sync to file for faster future checks
        const state: InstallationState = {
          isInstalled: true,
          installedAt: dbState.installedAt?.toISOString(),
          version: dbState.version,
          adminDiscordId: dbState.installedBy || undefined,
        }
        await saveInstallationState(state)
        return state
      }
    } catch {
      // Database not available or not set up
    }

    return { isInstalled: false, version: '1.0.0' }
  } catch {
    return { isInstalled: false, version: '1.0.0' }
  }
}

export async function saveInstallationState(state: InstallationState): Promise<void> {
  await fs.mkdir(CONFIG_DIR, { recursive: true })
  await fs.writeFile(INSTALLED_FILE, JSON.stringify(state, null, 2))
}

export function generateDatabaseUrl(config: InstallationConfig): string {
  return `mysql://${config.dbUser}:${encodeURIComponent(config.dbPassword)}@${config.dbHost}:${config.dbPort}/${config.dbName}`
}

export async function testDatabaseConnection(config: InstallationConfig): Promise<{ success: boolean; error?: string }> {
  // In a real implementation, this would test the MySQL connection
  // For now, we'll do basic validation
  try {
    if (!config.dbHost || !config.dbUser || !config.dbName) {
      return { success: false, error: 'Missing required database fields' }
    }

    // Attempt to create a test connection
    const mysql2 = await import('mysql2/promise').catch(() => null)
    if (mysql2) {
      const connection = await mysql2.createConnection({
        host: config.dbHost,
        port: config.dbPort,
        user: config.dbUser,
        password: config.dbPassword,
        database: config.dbName,
        connectTimeout: 5000,
      })
      await connection.ping()
      await connection.end()
    }

    return { success: true }
  } catch (error) {
    return { 
      success: false, 
      error: error instanceof Error ? error.message : 'Connection failed' 
    }
  }
}

export async function generateEnvFile(config: InstallationConfig): Promise<string> {
  const finalUrl = config.useDirectIp
    ? `http://localhost:3000`
    : config.subdomain
    ? `https://${config.subdomain}.${config.mainDomain}`
    : `https://${config.mainDomain}`

  const gameDbUrl = `mysql://${config.gameDbUser}:${encodeURIComponent(config.gameDbPassword)}@${config.gameDbHost}:${config.gameDbPort}/${config.gameDbName}`
  
  const envContent = `# SKG UCP Configuration
# Generated at: ${new Date().toISOString()}

# UCP Database (Prisma)
DATABASE_URL="${generateDatabaseUrl(config)}"

# FiveM Game Database
GAME_DATABASE_URL="${gameDbUrl}"
GAME_DATABASE_HOST="${config.gameDbHost}"
GAME_DATABASE_PORT="${config.gameDbPort}"
GAME_DATABASE_NAME="${config.gameDbName}"
GAME_DATABASE_USER="${config.gameDbUser}"
GAME_DATABASE_PASSWORD="${config.gameDbPassword}"
GAME_DATABASE_FRAMEWORK="${config.gameDbFramework}"

# Discord OAuth
DISCORD_CLIENT_ID="${config.discordClientId}"
DISCORD_CLIENT_SECRET="${config.discordClientSecret}"
DISCORD_CALLBACK_URL="${config.discordCallbackUrl || `${finalUrl}/api/auth/discord/callback`}"

# Discord Webhook (optional)
${config.discordWebhookUrl ? `DISCORD_WEBHOOK_URL="${config.discordWebhookUrl}"` : '# DISCORD_WEBHOOK_URL=""'}

# Security
JWT_SECRET="${config.jwtSecret}"
SESSION_DURATION_DAYS="${config.sessionDuration}"

# Application
NEXT_PUBLIC_APP_URL="${finalUrl}"
NEXT_PUBLIC_PANEL_NAME="${config.panelName}"

# Timezone
TZ="${config.timezone}"

# Installation State
INSTALLATION_COMPLETE="true"
INSTALLATION_DATE="${new Date().toISOString()}"
ADMIN_DISCORD_ID="${config.adminDiscordId}"
APP_VERSION="1.0.0"
`

  return envContent
}

export async function writeEnvFile(content: string): Promise<void> {
  // Write to .env.local (Next.js standard)
  const envLocalPath = path.join(APP_ROOT, '.env.local')
  await fs.writeFile(envLocalPath, content)
  
  // Also update the main .env file if it exists (for Linux installations)
  const envPath = path.join(APP_ROOT, '.env')
  try {
    let existingEnv = ''
    try {
      existingEnv = await fs.readFile(envPath, 'utf8')
    } catch {
      // .env doesn't exist, that's fine
    }
    
    // Add INSTALLATION_COMPLETE to existing .env if not already present
    if (existingEnv && !existingEnv.includes('INSTALLATION_COMPLETE=')) {
      const appendContent = `
# Installation State (added by web installer)
INSTALLATION_COMPLETE="true"
INSTALLATION_DATE="${new Date().toISOString()}"
`
      await fs.appendFile(envPath, appendContent)
    }
  } catch (error) {
    console.error('[Installation] Could not update .env file:', error)
    // Don't fail installation if this doesn't work
  }
}

export function generateJwtSecret(): string {
  return crypto.randomBytes(64).toString('hex')
}

export async function runInstallation(config: InstallationConfig): Promise<{ success: boolean; error?: string }> {
  try {
    // 1. Generate and write .env file
    const envContent = await generateEnvFile(config)
    await writeEnvFile(envContent)

    // 2. Initialize database schema (Prisma)
    // In production, this would run: npx prisma db push
    // For now, we assume the schema is already pushed

    // 3. Create branding settings
    await prisma.brandingSetting.upsert({
      where: { id: 'default' },
      create: {
        id: 'default',
        panelName: config.panelName,
        logoUrl: config.logoUrl,
        backgroundUrl: config.backgroundUrl,
        primaryColor: config.primaryColor,
        secondaryColor: config.secondaryColor,
        themeStyle: config.themeStyle,
      },
      update: {
        panelName: config.panelName,
        logoUrl: config.logoUrl,
        backgroundUrl: config.backgroundUrl,
        primaryColor: config.primaryColor,
        secondaryColor: config.secondaryColor,
        themeStyle: config.themeStyle,
      },
    })

    // 4. Create domain settings
    const finalUrl = config.useDirectIp
      ? undefined
      : config.subdomain
      ? `https://${config.subdomain}.${config.mainDomain}`
      : `https://${config.mainDomain}`

    await prisma.domainSetting.upsert({
      where: { id: 'default' },
      create: {
        id: 'default',
        useDirectIp: config.useDirectIp,
        mainDomain: config.mainDomain,
        subdomain: config.subdomain,
        finalUrl,
        nginxConfig: generateNginxConfig(config),
        apacheConfig: generateApacheConfig(config),
      },
      update: {
        useDirectIp: config.useDirectIp,
        mainDomain: config.mainDomain,
        subdomain: config.subdomain,
        finalUrl,
        nginxConfig: generateNginxConfig(config),
        apacheConfig: generateApacheConfig(config),
      },
    })

    // 5. Create system settings
    const settings = [
      { key: 'timezone', value: config.timezone, category: 'general' },
      { key: 'defaultLanguage', value: config.defaultLanguage, category: 'general' },
      { key: 'discordClientId', value: config.discordClientId, category: 'discord' },
      { key: 'discordWebhookUrl', value: config.discordWebhookUrl || '', category: 'discord' },
      { key: 'sessionDuration', value: String(config.sessionDuration), category: 'security' },
    ]

    for (const setting of settings) {
      await prisma.systemSetting.upsert({
        where: { key: setting.key },
        create: setting,
        update: { value: setting.value },
      })
    }

    // 6. Save FiveM game database configuration
    const frameworkMap = { 'auto': 'ESX', 'esx': 'ESX', 'qbcore': 'QBCORE' } as const
    await prisma.gameDatabaseConfig.upsert({
      where: { id: 'default' },
      create: {
        id: 'default',
        host: config.gameDbHost,
        port: config.gameDbPort,
        database: config.gameDbName,
        user: config.gameDbUser,
        password: config.gameDbPassword,
        framework: frameworkMap[config.gameDbFramework] || 'ESX',
        isActive: true,
      },
      update: {
        host: config.gameDbHost,
        port: config.gameDbPort,
        database: config.gameDbName,
        user: config.gameDbUser,
        password: config.gameDbPassword,
        framework: frameworkMap[config.gameDbFramework] || 'ESX',
        isActive: true,
      },
    })

    // 7. Create superadmin user placeholder
    await prisma.user.upsert({
      where: { discordId: config.adminDiscordId },
      create: {
        discordId: config.adminDiscordId,
        username: 'Superadmin',
        role: 'SUPERADMIN',
      },
      update: {
        role: 'SUPERADMIN',
      },
    })

    // 8. Mark as installed
    await prisma.installationState.upsert({
      where: { id: 'default' },
      create: {
        id: 'default',
        isInstalled: true,
        installedAt: new Date(),
        installedBy: config.adminDiscordId,
        version: '1.0.0',
        installData: config as unknown as Record<string, unknown>,
      },
      update: {
        isInstalled: true,
        installedAt: new Date(),
        installedBy: config.adminDiscordId,
        version: '1.0.0',
      },
    })

    // 9. Save local installation state
    await saveInstallationState({
      isInstalled: true,
      installedAt: new Date().toISOString(),
      version: '1.0.0',
      adminDiscordId: config.adminDiscordId,
    })

    // 10. Log installation
    await createAuditLog({
      action: 'SYSTEM_INSTALLED',
      category: 'INSTALLATION',
      details: {
        panelName: config.panelName,
        adminDiscordId: config.adminDiscordId,
        domain: finalUrl,
      },
      discordLog: {
        title: 'SKG UCP Installed',
        description: 'The panel has been successfully installed and configured.',
        fields: [
          { name: 'Panel Name', value: config.panelName, inline: true },
          { name: 'Version', value: '1.0.0', inline: true },
        ],
      },
    })

    return { success: true }
  } catch (error) {
    console.error('[Installation] Error:', error)
    return { 
      success: false, 
      error: error instanceof Error ? error.message : 'Installation failed' 
    }
  }
}

function generateNginxConfig(config: InstallationConfig): string {
  const serverName = config.subdomain
    ? `${config.subdomain}.${config.mainDomain}`
    : config.mainDomain || '_'

  return `# SKG UCP Nginx Configuration
# Place this in /etc/nginx/sites-available/skg-ucp

server {
    listen 80;
    server_name ${serverName};

    # Redirect HTTP to HTTPS
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name ${serverName};

    # SSL Configuration (update paths to your certificates)
    ssl_certificate /etc/letsencrypt/live/${serverName}/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/${serverName}/privkey.pem;

    # Security headers
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;

    # Proxy settings
    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_cache_bypass $http_upgrade;
    }

    # Static files
    location /_next/static {
        proxy_pass http://127.0.0.1:3000;
        proxy_cache_valid 60m;
        add_header Cache-Control "public, max-age=31536000, immutable";
    }
}
`
}

function generateApacheConfig(config: InstallationConfig): string {
  const serverName = config.subdomain
    ? `${config.subdomain}.${config.mainDomain}`
    : config.mainDomain || 'localhost'

  return `# SKG UCP Apache Configuration
# Place this in /etc/apache2/sites-available/skg-ucp.conf
# Enable required modules: a2enmod proxy proxy_http proxy_wstunnel ssl rewrite headers

<VirtualHost *:80>
    ServerName ${serverName}
    
    # Redirect to HTTPS
    RewriteEngine On
    RewriteCond %{HTTPS} off
    RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</VirtualHost>

<VirtualHost *:443>
    ServerName ${serverName}

    # SSL Configuration (update paths to your certificates)
    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/${serverName}/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/${serverName}/privkey.pem

    # Security headers
    Header always set X-Frame-Options "SAMEORIGIN"
    Header always set X-Content-Type-Options "nosniff"
    Header always set X-XSS-Protection "1; mode=block"

    # Proxy settings
    ProxyPreserveHost On
    ProxyPass / http://127.0.0.1:3000/
    ProxyPassReverse / http://127.0.0.1:3000/

    # WebSocket support
    RewriteEngine On
    RewriteCond %{HTTP:Upgrade} websocket [NC]
    RewriteCond %{HTTP:Connection} upgrade [NC]
    RewriteRule ^/?(.*) ws://127.0.0.1:3000/$1 [P,L]
</VirtualHost>
`
}

export async function resetInstallation(): Promise<{ success: boolean; error?: string }> {
  try {
    // Remove installation state file
    try {
      await fs.unlink(INSTALLED_FILE)
    } catch {
      // File doesn't exist
    }

    // Clear database installation state
    try {
      await prisma.installationState.updateMany({
        data: { isInstalled: false },
      })
    } catch {
      // Database might not be available
    }

    // Log reset
    await createAuditLog({
      action: 'SYSTEM_RESET',
      category: 'MAINTENANCE',
      discordLog: {
        title: 'SKG UCP Reset',
        description: 'The panel installation has been reset. Re-installation required.',
      },
    })

    return { success: true }
  } catch (error) {
    return { 
      success: false, 
      error: error instanceof Error ? error.message : 'Reset failed' 
    }
  }
}
