// Load environment config
const env = process.env.NODE_ENV || "dev";
const envFile = `.env.${env}`;
require("dotenv").config({ path: envFile });

const crypto = require("crypto");
const fs = require("fs");
const path = require("path");
const { AlphaInvitation, User, sequelize } = require("../models");
const emailServices = require("../services/email");
const logger = require("../utils/logger");

// Generate unique alpha code
async function generateUniqueAlphaCode() {
  let code;
  let exists = true;

  while (exists) {
    // Generate exactly 8 random alphanumeric characters
    const chars = "ABCDEFGHIJKLMNPQRSTUVWXYZ123456789";
    let randomStr = "";

    for (let i = 0; i < 8; i++) {
      const randomIndex = crypto.randomInt(0, chars.length);
      randomStr += chars[randomIndex];
    }

    code = `ALPHA-${randomStr}`;

    // Check if code exists
    const existing = await AlphaInvitation.findOne({ where: { code } });
    exists = !!existing;
  }

  return code;
}

// Normalize email
function normalizeEmail(email) {
  return email.toLowerCase().trim();
}

// Add invitation
async function addInvitation(email, notes = "") {
  try {
    email = normalizeEmail(email);

    // Check if invitation already exists for this email
    const existing = await AlphaInvitation.findOne({ where: { email } });
    if (existing) {
      console.log(`\n❌ Invitation already exists for ${email}`);
      console.log(`   Code: ${existing.code}`);
      console.log(`   Status: ${existing.status}`);
      console.log(`   Created: ${existing.createdAt}`);
      return null;
    }

    // Generate unique code
    const code = await generateUniqueAlphaCode();

    // Create invitation
    const invitation = await AlphaInvitation.create({
      code,
      email,
      status: "pending",
      notes,
    });

    // Send invitation email
    let emailSent = false;
    try {
      await emailServices.alphaInvitation.sendAlphaInvitation(email, code);
      emailSent = true;
    } catch (emailError) {
      console.log(`\n⚠️  Warning: Failed to send email to ${email}`);
      console.log(`   Error: ${emailError.message}`);
      console.log(`   Invitation created but email not sent.`);
    }

    console.log(`\n✅ Alpha invitation created successfully!`);
    console.log(`   Email: ${email}`);
    console.log(`   Code: ${code}`);
    console.log(`   Email sent: ${emailSent ? "Yes" : "No"}`);
    if (notes) {
      console.log(`   Notes: ${notes}`);
    }

    return invitation;
  } catch (error) {
    console.error(`\n❌ Error creating invitation: ${error.message}`);
    throw error;
  }
}

// Resend invitation
async function resendInvitation(emailOrCode) {
  try {
    const input = emailOrCode.trim();
    let invitation;

    // Try to find by code first (if it looks like a code), otherwise by email
    if (input.toUpperCase().startsWith("ALPHA-")) {
      invitation = await AlphaInvitation.findOne({
        where: { code: input.toUpperCase() }
      });
    } else {
      invitation = await AlphaInvitation.findOne({
        where: { email: normalizeEmail(input) }
      });
    }

    if (!invitation) {
      console.log(`\n❌ Invitation not found: ${input}`);
      return null;
    }

    // Check if revoked
    if (invitation.status === "revoked") {
      console.log(`\n❌ Cannot resend revoked invitation`);
      console.log(`   Code: ${invitation.code}`);
      console.log(`   Email: ${invitation.email}`);
      return null;
    }

    // Warn if already used
    if (invitation.usedBy) {
      console.log(`\n⚠️  Warning: This invitation has already been used`);
      console.log(`   Used by user ID: ${invitation.usedBy}`);
      console.log(`   Continuing with resend...\n`);
    }

    // Resend the email
    try {
      await emailServices.alphaInvitation.sendAlphaInvitation(invitation.email, invitation.code);

      console.log(`\n✅ Alpha invitation resent successfully!`);
      console.log(`   Email: ${invitation.email}`);
      console.log(`   Code: ${invitation.code}`);
      console.log(`   Status: ${invitation.status}`);

      return invitation;
    } catch (emailError) {
      console.error(`\n❌ Error sending email: ${emailError.message}`);
      throw emailError;
    }
  } catch (error) {
    console.error(`\n❌ Error resending invitation: ${error.message}`);
    throw error;
  }
}

// List invitations
async function listInvitations(filter = "all") {
  try {
    let where = {};

    if (filter === "pending") {
      where.status = "pending";
      where.usedBy = null;
    } else if (filter === "active") {
      where.status = "active";
    } else if (filter === "revoked") {
      where.status = "revoked";
    } else if (filter === "unused") {
      where.usedBy = null;
    }

    const invitations = await AlphaInvitation.findAll({
      where,
      include: [
        {
          model: User,
          as: "user",
          attributes: ["id", "email", "firstName", "lastName"],
        },
      ],
      order: [["createdAt", "DESC"]],
    });

    console.log(
      `\n📋 Alpha Invitations (${invitations.length} total, filter: ${filter})\n`
    );
    console.log("─".repeat(100));
    console.log(
      "CODE".padEnd(15) +
        "EMAIL".padEnd(30) +
        "STATUS".padEnd(10) +
        "USED BY".padEnd(25) +
        "CREATED"
    );
    console.log("─".repeat(100));

    if (invitations.length === 0) {
      console.log("No invitations found.");
    } else {
      invitations.forEach((inv) => {
        const usedBy = inv.user
          ? `${inv.user.firstName} ${inv.user.lastName}`
          : "-";
        const created = new Date(inv.createdAt).toLocaleDateString();

        console.log(
          inv.code.padEnd(15) +
            inv.email.padEnd(30) +
            inv.status.padEnd(10) +
            usedBy.padEnd(25) +
            created
        );
      });
    }
    console.log("─".repeat(100));

    // Summary
    const stats = {
      total: invitations.length,
      pending: invitations.filter((i) => i.status === "pending" && !i.usedBy)
        .length,
      active: invitations.filter((i) => i.status === "active" && i.usedBy)
        .length,
      revoked: invitations.filter((i) => i.status === "revoked").length,
    };

    console.log(
      `\nSummary: ${stats.pending} pending | ${stats.active} active | ${stats.revoked} revoked\n`
    );

    return invitations;
  } catch (error) {
    console.error(`\n❌ Error listing invitations: ${error.message}`);
    throw error;
  }
}

// Revoke invitation
async function revokeInvitation(code) {
  try {
    code = code.trim().toUpperCase();

    const invitation = await AlphaInvitation.findOne({ where: { code } });

    if (!invitation) {
      console.log(`\n❌ Invitation not found with code: ${code}`);
      return null;
    }

    if (invitation.status === "revoked") {
      console.log(`\n⚠️  Invitation is already revoked: ${code}`);
      return invitation;
    }

    await invitation.update({ status: "revoked" });

    console.log(`\n✅ Invitation revoked successfully!`);
    console.log(`   Code: ${code}`);
    console.log(`   Email: ${invitation.email}`);

    return invitation;
  } catch (error) {
    console.error(`\n❌ Error revoking invitation: ${error.message}`);
    throw error;
  }
}

// Restore invitation
async function restoreInvitation(code) {
  try {
    code = code.trim().toUpperCase();

    const invitation = await AlphaInvitation.findOne({ where: { code } });

    if (!invitation) {
      console.log(`\n❌ Invitation not found with code: ${code}`);
      return null;
    }

    if (invitation.status !== "revoked") {
      console.log(`\n⚠️  Invitation is not revoked (current status: ${invitation.status})`);
      console.log(`   Code: ${code}`);
      console.log(`   Email: ${invitation.email}`);
      return invitation;
    }

    // Determine the appropriate status to restore to
    const newStatus = invitation.usedBy ? "active" : "pending";

    await invitation.update({ status: newStatus });

    console.log(`\n✅ Invitation restored successfully!`);
    console.log(`   Code: ${code}`);
    console.log(`   Email: ${invitation.email}`);
    console.log(`   Status: ${newStatus} (${invitation.usedBy ? 'was previously used' : 'never used'})`);

    return invitation;
  } catch (error) {
    console.error(`\n❌ Error restoring invitation: ${error.message}`);
    throw error;
  }
}

// Bulk import from CSV
async function bulkImport(csvPath) {
  try {
    if (!fs.existsSync(csvPath)) {
      console.log(`\n❌ File not found: ${csvPath}`);
      return;
    }

    const csvContent = fs.readFileSync(csvPath, "utf-8");
    const lines = csvContent.split("\n").filter((line) => line.trim());

    // Skip header if present
    const hasHeader = lines[0].toLowerCase().includes("email");
    const dataLines = hasHeader ? lines.slice(1) : lines;

    console.log(
      `\n📥 Importing ${dataLines.length} invitations from ${csvPath}...\n`
    );

    let successCount = 0;
    let failCount = 0;

    for (const line of dataLines) {
      const [email, notes] = line.split(",").map((s) => s.trim());

      if (!email) {
        console.log(`⚠️  Skipping empty line`);
        failCount++;
        continue;
      }

      try {
        await addInvitation(email, notes || "");
        successCount++;
      } catch (error) {
        console.log(`❌ Failed to add ${email}: ${error.message}`);
        failCount++;
      }
    }

    console.log(`\n✅ Bulk import completed!`);
    console.log(`   Success: ${successCount}`);
    console.log(`   Failed: ${failCount}`);
    console.log(`   Total: ${dataLines.length}\n`);
  } catch (error) {
    console.error(`\n❌ Error during bulk import: ${error.message}`);
    throw error;
  }
}

// Main CLI handler
async function main() {
  const args = process.argv.slice(2);
  const command = args[0];

  try {
    // Verify database connection
    await sequelize.authenticate();

    if (!command || command === "help") {
      console.log(`
Alpha Invitation Management CLI

Usage:
  node scripts/manageAlphaInvitations.js <command> [options]

Commands:
  add <email> [notes]          Add a new alpha invitation
  list [filter]                List all invitations (filter: all|pending|active|revoked|unused)
  revoke <code>                Revoke an invitation code
  restore <code>               Restore a revoked invitation
  resend <email|code>          Resend an invitation email
  bulk <csvPath>               Bulk import invitations from CSV file

Examples:
  node scripts/manageAlphaInvitations.js add alice@example.com "Product team"
  node scripts/manageAlphaInvitations.js list pending
  node scripts/manageAlphaInvitations.js revoke ALPHA-ABC12345
  node scripts/manageAlphaInvitations.js restore ALPHA-ABC12345
  node scripts/manageAlphaInvitations.js resend alice@example.com
  node scripts/manageAlphaInvitations.js bulk invitations.csv

CSV Format:
  email,notes
  alice@example.com,Product team
  bob@example.com,Early adopter
      `);
    } else if (command === "add") {
      const email = args[1];
      const notes = args.slice(2).join(" ");

      if (!email) {
        console.log("\n❌ Error: Email is required");
        console.log(
          "Usage: node scripts/manageAlphaInvitations.js add <email> [notes]\n"
        );
        process.exit(1);
      }

      await addInvitation(email, notes);
    } else if (command === "list") {
      const filter = args[1] || "all";
      await listInvitations(filter);
    } else if (command === "revoke") {
      const code = args[1];

      if (!code) {
        console.log("\n❌ Error: Code is required");
        console.log(
          "Usage: node scripts/manageAlphaInvitations.js revoke <code>\n"
        );
        process.exit(1);
      }

      await revokeInvitation(code);
    } else if (command === "resend") {
      const emailOrCode = args[1];

      if (!emailOrCode) {
        console.log("\n❌ Error: Email or code is required");
        console.log(
          "Usage: node scripts/manageAlphaInvitations.js resend <email|code>\n"
        );
        process.exit(1);
      }

      await resendInvitation(emailOrCode);
    } else if (command === "restore") {
      const code = args[1];

      if (!code) {
        console.log("\n❌ Error: Code is required");
        console.log(
          "Usage: node scripts/manageAlphaInvitations.js restore <code>\n"
        );
        process.exit(1);
      }

      await restoreInvitation(code);
    } else if (command === "bulk") {
      const csvPath = args[1];

      if (!csvPath) {
        console.log("\n❌ Error: CSV path is required");
        console.log(
          "Usage: node scripts/manageAlphaInvitations.js bulk <csvPath>\n"
        );
        process.exit(1);
      }

      await bulkImport(path.resolve(csvPath));
    } else {
      console.log(`\n❌ Unknown command: ${command}`);
      console.log(
        "Run 'node scripts/manageAlphaInvitations.js help' for usage information\n"
      );
      process.exit(1);
    }

    process.exit(0);
  } catch (error) {
    console.error(`\n❌ Fatal error: ${error.message}`);
    console.error(error.stack);
    process.exit(1);
  }
}

// Run if called directly
if (require.main === module) {
  main();
}

module.exports = {
  addInvitation,
  listInvitations,
  revokeInvitation,
  restoreInvitation,
  resendInvitation,
  bulkImport,
  generateUniqueAlphaCode,
};
