import { PrismaClient, OrderStatus, SubscriptionPlan, SubscriptionTier, SubscriptionStatus, UserStatus, LogLevel } from '@prisma/client'
import bcrypt from 'bcryptjs'

const { hash } = bcrypt

const prisma = new PrismaClient()

// Random data helpers
const companies = [
  'Acme Corp', 'TechStart Inc', 'Digital Solutions', 'CloudFirst Ltd',
  'InnovateTech', 'DataDriven Co', 'SmartBiz Solutions', 'FutureTech Labs',
  'AgileWorks', 'NextGen Systems', null, null, null
]

const domains = [
  'acme.letsbe.cloud', 'techstart.letsbe.cloud', 'digital.letsbe.cloud',
  'cloudfirst.letsbe.cloud', 'innovate.letsbe.cloud', 'datadriven.letsbe.cloud',
  'smartbiz.letsbe.cloud', 'futuretech.letsbe.cloud', 'agileworks.letsbe.cloud',
  'nextgen.letsbe.cloud', 'startup.letsbe.cloud', 'enterprise.letsbe.cloud',
  'demo.letsbe.cloud', 'test.letsbe.cloud', 'dev.letsbe.cloud'
]

const toolSets = {
  basic: ['nextcloud', 'keycloak'],
  standard: ['nextcloud', 'keycloak', 'minio', 'poste'],
  advanced: ['nextcloud', 'keycloak', 'minio', 'poste', 'n8n', 'filebrowser'],
  full: ['nextcloud', 'keycloak', 'minio', 'poste', 'n8n', 'filebrowser', 'portainer', 'grafana'],
}

const logMessages = {
  PAYMENT_CONFIRMED: ['Payment received via Stripe', 'Order confirmed'],
  AWAITING_SERVER: ['Waiting for server allocation', 'Server request submitted to provider'],
  SERVER_READY: ['Server provisioned', 'SSH access verified', 'Root password received'],
  DNS_PENDING: ['DNS records submitted', 'Waiting for DNS propagation'],
  DNS_READY: ['DNS records verified', 'Domain is resolving correctly'],
  PROVISIONING: [
    'Starting provisioning process',
    'Downloading Docker images',
    'Configuring Nginx reverse proxy',
    'Installing Keycloak',
    'Configuring Nextcloud',
    'Setting up MinIO storage',
    'Configuring email server',
    'Running health checks',
  ],
  FULFILLED: ['Provisioning complete', 'All services healthy', 'Welcome email sent'],
  EMAIL_CONFIGURED: ['SMTP credentials configured', 'Email sending verified'],
  FAILED: ['Provisioning failed', 'See error details below'],
}

function randomDate(daysAgo: number): Date {
  const date = new Date()
  date.setDate(date.getDate() - Math.floor(Math.random() * daysAgo))
  date.setHours(Math.floor(Math.random() * 24))
  date.setMinutes(Math.floor(Math.random() * 60))
  return date
}

function randomChoice<T>(arr: T[]): T {
  return arr[Math.floor(Math.random() * arr.length)]
}

async function main() {
  console.log('Starting seed...')

  // 1. Create admin user if not exists
  const adminEmail = process.env.ADMIN_EMAIL || 'admin@letsbe.solutions'
  const adminPassword = process.env.ADMIN_PASSWORD || 'admin123'

  const existingAdmin = await prisma.staff.findUnique({
    where: { email: adminEmail },
  })

  if (!existingAdmin) {
    const passwordHash = await hash(adminPassword, 12)
    await prisma.staff.create({
      data: {
        email: adminEmail,
        passwordHash,
        name: 'Admin',
        role: 'ADMIN',
      },
    })
    console.log(`Created admin user: ${adminEmail}`)
  } else {
    console.log(`Admin user ${adminEmail} already exists`)
  }

  // 2. Create support staff
  const supportEmail = 'support@letsbe.solutions'
  const existingSupport = await prisma.staff.findUnique({
    where: { email: supportEmail },
  })

  if (!existingSupport) {
    const passwordHash = await hash('support123', 12)
    await prisma.staff.create({
      data: {
        email: supportEmail,
        passwordHash,
        name: 'Support Agent',
        role: 'SUPPORT',
      },
    })
    console.log(`Created support user: ${supportEmail}`)
  }

  // 3. Create test customers
  const customerData = [
    { email: 'john@acme.com', name: 'John Smith', company: 'Acme Corp', status: UserStatus.ACTIVE },
    { email: 'sarah@techstart.io', name: 'Sarah Johnson', company: 'TechStart Inc', status: UserStatus.ACTIVE },
    { email: 'mike@cloudfirst.co', name: 'Mike Davis', company: 'CloudFirst Ltd', status: UserStatus.ACTIVE },
    { email: 'emma@digital.io', name: 'Emma Wilson', company: 'Digital Solutions', status: UserStatus.ACTIVE },
    { email: 'david@innovate.co', name: 'David Brown', company: 'InnovateTech', status: UserStatus.ACTIVE },
    { email: 'lisa@datadriven.io', name: 'Lisa Chen', company: 'DataDriven Co', status: UserStatus.ACTIVE },
    { email: 'james@smartbiz.com', name: 'James Miller', company: 'SmartBiz Solutions', status: UserStatus.ACTIVE },
    { email: 'amy@futuretech.io', name: 'Amy Taylor', company: 'FutureTech Labs', status: UserStatus.PENDING_VERIFICATION },
    { email: 'robert@agile.co', name: 'Robert Anderson', company: 'AgileWorks', status: UserStatus.ACTIVE },
    { email: 'jennifer@nextgen.io', name: 'Jennifer Lee', company: 'NextGen Systems', status: UserStatus.SUSPENDED },
    { email: 'freelancer@gmail.com', name: 'Alex Freelancer', company: null, status: UserStatus.ACTIVE },
    { email: 'startup@mail.com', name: 'Startup Founder', company: null, status: UserStatus.PENDING_VERIFICATION },
  ]

  const customers: { id: string; email: string }[] = []

  for (const customer of customerData) {
    const existing = await prisma.user.findUnique({
      where: { email: customer.email },
    })

    if (!existing) {
      const passwordHash = await hash('customer123', 12)
      const created = await prisma.user.create({
        data: {
          email: customer.email,
          passwordHash,
          name: customer.name,
          company: customer.company,
          status: customer.status,
          emailVerified: customer.status === UserStatus.ACTIVE ? new Date() : null,
        },
      })
      customers.push({ id: created.id, email: created.email })
      console.log(`Created customer: ${customer.email}`)
    } else {
      customers.push({ id: existing.id, email: existing.email })
      console.log(`Customer ${customer.email} already exists`)
    }
  }

  // 4. Create subscriptions for customers
  const subscriptionConfigs = [
    { plan: SubscriptionPlan.ENTERPRISE, tier: SubscriptionTier.HUB_DASHBOARD, status: SubscriptionStatus.ACTIVE },
    { plan: SubscriptionPlan.PRO, tier: SubscriptionTier.HUB_DASHBOARD, status: SubscriptionStatus.ACTIVE },
    { plan: SubscriptionPlan.PRO, tier: SubscriptionTier.ADVANCED, status: SubscriptionStatus.ACTIVE },
    { plan: SubscriptionPlan.STARTER, tier: SubscriptionTier.ADVANCED, status: SubscriptionStatus.ACTIVE },
    { plan: SubscriptionPlan.STARTER, tier: SubscriptionTier.ADVANCED, status: SubscriptionStatus.ACTIVE },
    { plan: SubscriptionPlan.PRO, tier: SubscriptionTier.HUB_DASHBOARD, status: SubscriptionStatus.PAST_DUE },
    { plan: SubscriptionPlan.STARTER, tier: SubscriptionTier.ADVANCED, status: SubscriptionStatus.ACTIVE },
    { plan: SubscriptionPlan.TRIAL, tier: SubscriptionTier.HUB_DASHBOARD, status: SubscriptionStatus.TRIAL },
    { plan: SubscriptionPlan.ENTERPRISE, tier: SubscriptionTier.HUB_DASHBOARD, status: SubscriptionStatus.CANCELED },
    { plan: SubscriptionPlan.STARTER, tier: SubscriptionTier.ADVANCED, status: SubscriptionStatus.ACTIVE },
    { plan: SubscriptionPlan.TRIAL, tier: SubscriptionTier.ADVANCED, status: SubscriptionStatus.TRIAL },
    { plan: SubscriptionPlan.TRIAL, tier: SubscriptionTier.HUB_DASHBOARD, status: SubscriptionStatus.TRIAL },
  ]

  for (let i = 0; i < customers.length; i++) {
    const customer = customers[i]
    const config = subscriptionConfigs[i] || subscriptionConfigs[0]

    const existingSub = await prisma.subscription.findFirst({
      where: { userId: customer.id },
    })

    if (!existingSub) {
      await prisma.subscription.create({
        data: {
          userId: customer.id,
          plan: config.plan,
          tier: config.tier,
          status: config.status,
          tokenLimit: config.plan === SubscriptionPlan.ENTERPRISE ? 100000 :
                      config.plan === SubscriptionPlan.PRO ? 50000 :
                      config.plan === SubscriptionPlan.STARTER ? 20000 : 10000,
          tokensUsed: Math.floor(Math.random() * 5000),
          trialEndsAt: config.status === SubscriptionStatus.TRIAL ?
            new Date(Date.now() + 14 * 24 * 60 * 60 * 1000) : null,
        },
      })
      console.log(`Created subscription for: ${customer.email}`)
    }
  }

  // 5. Create orders with various statuses
  const orderConfigs = [
    // Orders in various pipeline stages
    { status: OrderStatus.PAYMENT_CONFIRMED, tier: SubscriptionTier.HUB_DASHBOARD },
    { status: OrderStatus.PAYMENT_CONFIRMED, tier: SubscriptionTier.ADVANCED },
    { status: OrderStatus.AWAITING_SERVER, tier: SubscriptionTier.HUB_DASHBOARD },
    { status: OrderStatus.AWAITING_SERVER, tier: SubscriptionTier.ADVANCED },
    { status: OrderStatus.SERVER_READY, tier: SubscriptionTier.HUB_DASHBOARD },
    { status: OrderStatus.DNS_PENDING, tier: SubscriptionTier.ADVANCED },
    { status: OrderStatus.DNS_PENDING, tier: SubscriptionTier.HUB_DASHBOARD },
    { status: OrderStatus.DNS_READY, tier: SubscriptionTier.HUB_DASHBOARD },
    { status: OrderStatus.DNS_READY, tier: SubscriptionTier.ADVANCED },
    { status: OrderStatus.PROVISIONING, tier: SubscriptionTier.HUB_DASHBOARD },
    { status: OrderStatus.FULFILLED, tier: SubscriptionTier.ADVANCED },
    { status: OrderStatus.FULFILLED, tier: SubscriptionTier.HUB_DASHBOARD },
    { status: OrderStatus.FULFILLED, tier: SubscriptionTier.ADVANCED },
    { status: OrderStatus.EMAIL_CONFIGURED, tier: SubscriptionTier.HUB_DASHBOARD },
    { status: OrderStatus.EMAIL_CONFIGURED, tier: SubscriptionTier.ADVANCED },
    { status: OrderStatus.FAILED, tier: SubscriptionTier.HUB_DASHBOARD },
  ]

  for (let i = 0; i < orderConfigs.length; i++) {
    const config = orderConfigs[i]
    const customer = customers[i % customers.length]
    const domain = domains[i % domains.length]

    const existingOrder = await prisma.order.findFirst({
      where: { domain },
    })

    if (!existingOrder) {
      const tools = config.tier === SubscriptionTier.HUB_DASHBOARD
        ? toolSets.full
        : randomChoice([toolSets.basic, toolSets.standard, toolSets.advanced])

      const createdAt = randomDate(30)
      const serverStatuses: OrderStatus[] = [
        OrderStatus.SERVER_READY, OrderStatus.DNS_PENDING, OrderStatus.DNS_READY,
        OrderStatus.PROVISIONING, OrderStatus.FULFILLED, OrderStatus.EMAIL_CONFIGURED,
        OrderStatus.FAILED
      ]
      const hasServer = serverStatuses.includes(config.status)

      const order = await prisma.order.create({
        data: {
          userId: customer.id,
          status: config.status,
          tier: config.tier,
          domain,
          tools,
          configJson: { tools, tier: config.tier, domain },
          serverIp: hasServer ? `192.168.1.${100 + i}` : null,
          serverPasswordEncrypted: hasServer ? 'encrypted_placeholder' : null,
          sshPort: 22,
          portainerUrl: config.status === OrderStatus.FULFILLED || config.status === OrderStatus.EMAIL_CONFIGURED
            ? `https://portainer.${domain}` : null,
          dashboardUrl: config.status === OrderStatus.FULFILLED || config.status === OrderStatus.EMAIL_CONFIGURED
            ? `https://dashboard.${domain}` : null,
          failureReason: config.status === OrderStatus.FAILED
            ? 'Connection timeout during Docker installation' : null,
          createdAt,
          serverReadyAt: hasServer ? new Date(createdAt.getTime() + 2 * 60 * 60 * 1000) : null,
          provisioningStartedAt: config.status === OrderStatus.PROVISIONING ||
            config.status === OrderStatus.FULFILLED || config.status === OrderStatus.EMAIL_CONFIGURED
            ? new Date(createdAt.getTime() + 4 * 60 * 60 * 1000) : null,
          completedAt: config.status === OrderStatus.FULFILLED || config.status === OrderStatus.EMAIL_CONFIGURED
            ? new Date(createdAt.getTime() + 5 * 60 * 60 * 1000) : null,
        },
      })

      // Add provisioning logs based on status
      const statusIndex = Object.keys(logMessages).indexOf(config.status)
      const statusesToLog = Object.keys(logMessages).slice(0, statusIndex + 1) as OrderStatus[]

      let logTime = new Date(createdAt)
      for (const logStatus of statusesToLog) {
        const messages = logMessages[logStatus] || []
        for (const message of messages) {
          await prisma.provisioningLog.create({
            data: {
              orderId: order.id,
              level: logStatus === OrderStatus.FAILED ? LogLevel.ERROR : LogLevel.INFO,
              message,
              step: logStatus,
              timestamp: new Date(logTime),
            },
          })
          logTime = new Date(logTime.getTime() + Math.random() * 5 * 60 * 1000) // 0-5 min later
        }
      }

      console.log(`Created order: ${domain} (${config.status})`)
    }
  }

  // 6. Create a runner token for testing
  const runnerTokenHash = await hash('test-runner-token', 12)
  const existingRunner = await prisma.runnerToken.findFirst({
    where: { name: 'test-runner' },
  })

  if (!existingRunner) {
    await prisma.runnerToken.create({
      data: {
        tokenHash: runnerTokenHash,
        name: 'test-runner',
        isActive: true,
      },
    })
    console.log('Created test runner token')
  }

  console.log('\nSeed completed successfully!')
  console.log('\nTest credentials:')
  console.log('  Admin: admin@letsbe.solutions / admin123')
  console.log('  Support: support@letsbe.solutions / support123')
  console.log('  Customers: <email> / customer123')
}

main()
  .catch((e) => {
    console.error(e)
    process.exit(1)
  })
  .finally(async () => {
    await prisma.$disconnect()
  })
