import 'dotenv/config';
import { Client, Databases, ID, Permission, Role } from "node-appwrite";

/**
 * MailFlow Database Bootstrap Script v2
 * Creates all required collections for the full MailFlow app
 */

const requiredEnv = [
  "APPWRITE_ENDPOINT",
  "APPWRITE_PROJECT_ID",
  "APPWRITE_API_KEY",
];

for (const k of requiredEnv) {
  if (!process.env[k]) {
    console.error(`Missing env var: ${k}`);
    process.exit(1);
  }
}

const client = new Client()
  .setEndpoint(process.env.APPWRITE_ENDPOINT)
  .setProject(process.env.APPWRITE_PROJECT_ID)
  .setKey(process.env.APPWRITE_API_KEY);

const db = new Databases(client);

const DB_ID = process.env.APPWRITE_DATABASE_ID || 'mailflow';
const DB_NAME = 'MailFlow';

// Helper: create database if not exists
async function ensureDatabase() {
  try {
    await db.get(DB_ID);
    console.log("✓ Database exists:", DB_ID);
  } catch {
    await db.create(DB_ID, DB_NAME);
    console.log("✓ Database created:", DB_ID);
  }
}

// Helper: create collection if not exists
async function ensureCollection(collectionId, name, permissions = []) {
  try {
    await db.getCollection(DB_ID, collectionId);
    console.log(`✓ Collection exists: ${collectionId}`);
  } catch {
    await db.createCollection(DB_ID, collectionId, name, permissions, true);
    console.log(`✓ Collection created: ${collectionId}`);
  }
}

// Helper: create attribute if not exists
async function ensureAttribute(collectionId, key, createFn) {
  const attributes = await db.listAttributes(DB_ID, collectionId);
  const exists = attributes.attributes?.some(a => a.key === key);
  if (exists) {
    console.log(`  - Attribute exists: ${collectionId}.${key}`);
    return;
  }
  await createFn();
  console.log(`  + Attribute created: ${collectionId}.${key}`);
  // Wait for attribute to be ready
  await new Promise(resolve => setTimeout(resolve, 1000));
}

// Permission templates
const PERM_PUBLIC_READ = [Permission.read(Role.any())];
const PERM_AUTHENTICATED = [
  Permission.read(Role.users()),
  Permission.create(Role.users()),
];
const PERM_SERVER_ONLY = [];

async function setupCollections() {
  // ==================== Products ====================
  await ensureCollection('products', 'Products', PERM_PUBLIC_READ);
  await ensureAttribute('products', 'slug', () =>
    db.createStringAttribute(DB_ID, 'products', 'slug', 128, true));
  await ensureAttribute('products', 'title', () =>
    db.createStringAttribute(DB_ID, 'products', 'title', 256, true));
  await ensureAttribute('products', 'description', () =>
    db.createStringAttribute(DB_ID, 'products', 'description', 4096, false));
  await ensureAttribute('products', 'priceCents', () =>
    db.createIntegerAttribute(DB_ID, 'products', 'priceCents', true, 0, 999999999));
  await ensureAttribute('products', 'currency', () =>
    db.createStringAttribute(DB_ID, 'products', 'currency', 8, true));
  await ensureAttribute('products', 'isActive', () =>
    db.createBooleanAttribute(DB_ID, 'products', 'isActive', true));

  // ==================== Questions ====================
  await ensureCollection('questions', 'Questions', PERM_PUBLIC_READ);
  await ensureAttribute('questions', 'productId', () =>
    db.createStringAttribute(DB_ID, 'questions', 'productId', 64, true));
  await ensureAttribute('questions', 'key', () =>
    db.createStringAttribute(DB_ID, 'questions', 'key', 64, true));
  await ensureAttribute('questions', 'label', () =>
    db.createStringAttribute(DB_ID, 'questions', 'label', 256, true));
  await ensureAttribute('questions', 'helpText', () =>
    db.createStringAttribute(DB_ID, 'questions', 'helpText', 1024, false));
  await ensureAttribute('questions', 'type', () =>
    db.createStringAttribute(DB_ID, 'questions', 'type', 32, true));
  await ensureAttribute('questions', 'required', () =>
    db.createBooleanAttribute(DB_ID, 'questions', 'required', true));
  await ensureAttribute('questions', 'step', () =>
    db.createIntegerAttribute(DB_ID, 'questions', 'step', true, 1, 9999));
  await ensureAttribute('questions', 'order', () =>
    db.createIntegerAttribute(DB_ID, 'questions', 'order', true, 1, 999999));
  await ensureAttribute('questions', 'optionsJson', () =>
    db.createStringAttribute(DB_ID, 'questions', 'optionsJson', 8192, false));
  await ensureAttribute('questions', 'isActive', () =>
    db.createBooleanAttribute(DB_ID, 'questions', 'isActive', true));

  // ==================== Submissions ====================
  await ensureCollection('submissions', 'Submissions', PERM_AUTHENTICATED);
  await ensureAttribute('submissions', 'productId', () =>
    db.createStringAttribute(DB_ID, 'submissions', 'productId', 64, true));
  await ensureAttribute('submissions', 'status', () =>
    db.createStringAttribute(DB_ID, 'submissions', 'status', 32, true));
  await ensureAttribute('submissions', 'customerEmail', () =>
    db.createEmailAttribute(DB_ID, 'submissions', 'customerEmail', false));
  await ensureAttribute('submissions', 'customerName', () =>
    db.createStringAttribute(DB_ID, 'submissions', 'customerName', 256, false));
  await ensureAttribute('submissions', 'finalSummaryJson', () =>
    db.createStringAttribute(DB_ID, 'submissions', 'finalSummaryJson', 16384, false));
  await ensureAttribute('submissions', 'priceCents', () =>
    db.createIntegerAttribute(DB_ID, 'submissions', 'priceCents', true, 0, 999999999));
  await ensureAttribute('submissions', 'currency', () =>
    db.createStringAttribute(DB_ID, 'submissions', 'currency', 8, true));

  // ==================== Answers ====================
  await ensureCollection('answers', 'Answers', PERM_AUTHENTICATED);
  await ensureAttribute('answers', 'submissionId', () =>
    db.createStringAttribute(DB_ID, 'answers', 'submissionId', 64, true));
  await ensureAttribute('answers', 'answersJson', () =>
    db.createStringAttribute(DB_ID, 'answers', 'answersJson', 16384, true));

  // ==================== Orders ====================
  await ensureCollection('orders', 'Orders', PERM_SERVER_ONLY);
  await ensureAttribute('orders', 'submissionId', () =>
    db.createStringAttribute(DB_ID, 'orders', 'submissionId', 64, true));
  await ensureAttribute('orders', 'orderDataJson', () =>
    db.createStringAttribute(DB_ID, 'orders', 'orderDataJson', 16384, true));

  // ==================== Email Accounts ====================
  await ensureCollection('email_accounts', 'Email Accounts', PERM_AUTHENTICATED);
  await ensureAttribute('email_accounts', 'userId', () =>
    db.createStringAttribute(DB_ID, 'email_accounts', 'userId', 64, true));
  await ensureAttribute('email_accounts', 'provider', () =>
    db.createStringAttribute(DB_ID, 'email_accounts', 'provider', 32, true));
  await ensureAttribute('email_accounts', 'email', () =>
    db.createEmailAttribute(DB_ID, 'email_accounts', 'email', true));
  await ensureAttribute('email_accounts', 'accessToken', () =>
    db.createStringAttribute(DB_ID, 'email_accounts', 'accessToken', 4096, false));
  await ensureAttribute('email_accounts', 'refreshToken', () =>
    db.createStringAttribute(DB_ID, 'email_accounts', 'refreshToken', 4096, false));
  await ensureAttribute('email_accounts', 'expiresAt', () =>
    db.createIntegerAttribute(DB_ID, 'email_accounts', 'expiresAt', false));
  await ensureAttribute('email_accounts', 'isActive', () =>
    db.createBooleanAttribute(DB_ID, 'email_accounts', 'isActive', true));
  await ensureAttribute('email_accounts', 'lastSync', () =>
    db.createDatetimeAttribute(DB_ID, 'email_accounts', 'lastSync', false));
  await ensureAttribute('email_accounts', 'imapHost', () =>
    db.createStringAttribute(DB_ID, 'email_accounts', 'imapHost', 256, false));
  await ensureAttribute('email_accounts', 'imapPort', () =>
    db.createIntegerAttribute(DB_ID, 'email_accounts', 'imapPort', false));
  await ensureAttribute('email_accounts', 'imapSecure', () =>
    db.createBooleanAttribute(DB_ID, 'email_accounts', 'imapSecure', false));

  // ==================== Email Stats ====================
  await ensureCollection('email_stats', 'Email Stats', PERM_AUTHENTICATED);
  await ensureAttribute('email_stats', 'userId', () =>
    db.createStringAttribute(DB_ID, 'email_stats', 'userId', 64, true));
  await ensureAttribute('email_stats', 'totalSorted', () =>
    db.createIntegerAttribute(DB_ID, 'email_stats', 'totalSorted', true, 0));
  await ensureAttribute('email_stats', 'todaySorted', () =>
    db.createIntegerAttribute(DB_ID, 'email_stats', 'todaySorted', true, 0));
  await ensureAttribute('email_stats', 'weekSorted', () =>
    db.createIntegerAttribute(DB_ID, 'email_stats', 'weekSorted', true, 0));
  await ensureAttribute('email_stats', 'categoriesJson', () =>
    db.createStringAttribute(DB_ID, 'email_stats', 'categoriesJson', 4096, false));
  await ensureAttribute('email_stats', 'timeSavedMinutes', () =>
    db.createIntegerAttribute(DB_ID, 'email_stats', 'timeSavedMinutes', true, 0));

  // ==================== Subscriptions ====================
  await ensureCollection('subscriptions', 'Subscriptions', PERM_AUTHENTICATED);
  await ensureAttribute('subscriptions', 'userId', () =>
    db.createStringAttribute(DB_ID, 'subscriptions', 'userId', 64, true));
  await ensureAttribute('subscriptions', 'stripeCustomerId', () =>
    db.createStringAttribute(DB_ID, 'subscriptions', 'stripeCustomerId', 128, false));
  await ensureAttribute('subscriptions', 'stripeSubscriptionId', () =>
    db.createStringAttribute(DB_ID, 'subscriptions', 'stripeSubscriptionId', 128, false));
  await ensureAttribute('subscriptions', 'plan', () =>
    db.createStringAttribute(DB_ID, 'subscriptions', 'plan', 32, true));
  await ensureAttribute('subscriptions', 'status', () =>
    db.createStringAttribute(DB_ID, 'subscriptions', 'status', 32, true));
  await ensureAttribute('subscriptions', 'currentPeriodEnd', () =>
    db.createDatetimeAttribute(DB_ID, 'subscriptions', 'currentPeriodEnd', false));
  await ensureAttribute('subscriptions', 'cancelAtPeriodEnd', () =>
    db.createBooleanAttribute(DB_ID, 'subscriptions', 'cancelAtPeriodEnd', false));

  // ==================== User Preferences ====================
  await ensureCollection('user_preferences', 'User Preferences', PERM_AUTHENTICATED);
  await ensureAttribute('user_preferences', 'userId', () =>
    db.createStringAttribute(DB_ID, 'user_preferences', 'userId', 64, true));
  await ensureAttribute('user_preferences', 'preferencesJson', () =>
    db.createStringAttribute(DB_ID, 'user_preferences', 'preferencesJson', 16384, false));

  // ==================== Onboarding State ====================
  await ensureCollection('onboarding_state', 'Onboarding State', PERM_AUTHENTICATED);
  await ensureAttribute('onboarding_state', 'userId', () =>
    db.createStringAttribute(DB_ID, 'onboarding_state', 'userId', 64, true));
  await ensureAttribute('onboarding_state', 'onboarding_step', () =>
    db.createStringAttribute(DB_ID, 'onboarding_state', 'onboarding_step', 32, true));
  await ensureAttribute('onboarding_state', 'completed_steps_json', () =>
    db.createStringAttribute(DB_ID, 'onboarding_state', 'completed_steps_json', 1024, false));
  await ensureAttribute('onboarding_state', 'first_value_seen_at', () =>
    db.createDatetimeAttribute(DB_ID, 'onboarding_state', 'first_value_seen_at', false));
  await ensureAttribute('onboarding_state', 'skipped_at', () =>
    db.createDatetimeAttribute(DB_ID, 'onboarding_state', 'skipped_at', false));
  await ensureAttribute('onboarding_state', 'last_updated', () =>
    db.createDatetimeAttribute(DB_ID, 'onboarding_state', 'last_updated', false));

  // ==================== Email Usage ====================
  await ensureCollection('email_usage', 'Email Usage', PERM_AUTHENTICATED);
  await ensureAttribute('email_usage', 'userId', () =>
    db.createStringAttribute(DB_ID, 'email_usage', 'userId', 64, true));
  await ensureAttribute('email_usage', 'month', () =>
    db.createStringAttribute(DB_ID, 'email_usage', 'month', 16, true)); // "2026-01"
  await ensureAttribute('email_usage', 'emailsProcessed', () =>
    db.createIntegerAttribute(DB_ID, 'email_usage', 'emailsProcessed', true, 0));
  await ensureAttribute('email_usage', 'lastReset', () =>
    db.createDatetimeAttribute(DB_ID, 'email_usage', 'lastReset', false));

  // ==================== Referrals ====================
  await ensureCollection('referrals', 'Referrals', PERM_AUTHENTICATED);
  await ensureAttribute('referrals', 'userId', () =>
    db.createStringAttribute(DB_ID, 'referrals', 'userId', 64, true));
  await ensureAttribute('referrals', 'referralCode', () =>
    db.createStringAttribute(DB_ID, 'referrals', 'referralCode', 32, true));
  await ensureAttribute('referrals', 'referredBy', () =>
    db.createStringAttribute(DB_ID, 'referrals', 'referredBy', 64, false));
  await ensureAttribute('referrals', 'referralCount', () =>
    db.createIntegerAttribute(DB_ID, 'referrals', 'referralCount', true, 0));
  await ensureAttribute('referrals', 'createdAt', () =>
    db.createDatetimeAttribute(DB_ID, 'referrals', 'createdAt', false));

  // ==================== Analytics Events ====================
  await ensureCollection('analytics_events', 'Analytics Events', PERM_PUBLIC_READ);
  await ensureAttribute('analytics_events', 'userId', () =>
    db.createStringAttribute(DB_ID, 'analytics_events', 'userId', 64, false));
  await ensureAttribute('analytics_events', 'eventType', () =>
    db.createStringAttribute(DB_ID, 'analytics_events', 'eventType', 64, true));
  await ensureAttribute('analytics_events', 'metadataJson', () =>
    db.createStringAttribute(DB_ID, 'analytics_events', 'metadataJson', 4096, false));
  await ensureAttribute('analytics_events', 'timestamp', () =>
    db.createDatetimeAttribute(DB_ID, 'analytics_events', 'timestamp', false));
  await ensureAttribute('analytics_events', 'sessionId', () =>
    db.createStringAttribute(DB_ID, 'analytics_events', 'sessionId', 64, false));
}

async function main() {
  console.log('\n========================================');
  console.log('  MailFlow Database Bootstrap v2');
  console.log('========================================\n');
  
  await ensureDatabase();
  console.log('\n--- Setting up collections ---\n');
  await setupCollections();
  
  console.log('\n========================================');
  console.log('  ✓ Bootstrap complete!');
  console.log(`  Database ID: ${DB_ID}`);
  console.log('========================================\n');
  console.log('Add this to your .env file:');
  console.log(`APPWRITE_DATABASE_ID=${DB_ID}\n`);
}

main().catch((e) => {
  console.error('Bootstrap failed:', e);
  process.exit(1);
});
