import crypto from 'crypto';
import dotenv from 'dotenv';
import mongoose from 'mongoose';
import path from 'path';
import Doctor from '../models/Doctor';
import Patient from '../models/Patient';
import User from '../models/User';

dotenv.config({ path: path.resolve(__dirname, '../../.env') });

const TARGET_MIN_PATIENTS = 160;

const TARGETS: Array<{ label: string; emails: string[] }> = [
  {
    label: 'doctor',
    emails: ['tejasimma033+doctor@gmail.com'],
  },
  {
    label: 'dentist',
    emails: ['tejasimma033+dentist@gmail.com', 'tejasimma033+dentist@gmail.come'],
  },
];

const FIRST_NAMES = [
  'James', 'Mary', 'John', 'Patricia', 'Robert', 'Jennifer', 'Michael', 'Linda',
  'William', 'Elizabeth', 'David', 'Barbara', 'Richard', 'Susan', 'Joseph', 'Jessica',
];
const LAST_NAMES = [
  'Smith', 'Johnson', 'Williams', 'Brown', 'Jones', 'Garcia', 'Miller', 'Davis',
  'Rodriguez', 'Martinez', 'Hernandez', 'Lopez', 'Gonzalez', 'Wilson', 'Anderson', 'Thomas',
];
const STREETS = ['Main St', 'Oak Ave', 'Pine Rd', 'Maple Ln', 'Cedar Blvd', 'Elm St'];
const GENDERS: Array<'Male' | 'Female'> = ['Male', 'Female'];

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

function randomDob(): Date {
  const start = new Date(1950, 0, 1).getTime();
  const end = new Date(2005, 0, 1).getTime();
  return new Date(start + Math.random() * (end - start));
}

function randomPhone(index: number): string {
  const serial = String(index).padStart(6, '0');
  return `+1555${serial}`;
}

async function getDoctorByEmails(emails: string[]) {
  const normalized = emails.map((email) => email.toLowerCase());
  const user = await User.findOne({ email: { $in: normalized } });
  if (!user) return null;
  const doctor = await Doctor.findOne({ userId: user._id });
  if (!doctor) return null;
  return { user, doctor };
}

async function createPatientForDoctor(doctorId: string, seed: string, index: number) {
  const firstName = pick(FIRST_NAMES);
  const lastName = pick(LAST_NAMES);
  const email = `bulk.${seed}.${Date.now()}.${index}.${crypto.randomBytes(2).toString('hex')}@example.com`;

  const user = await User.create({
    firstName,
    lastName,
    email,
    password: 'Patient1234!',
    userType: 'patient',
    phone: randomPhone(index),
    isActive: true,
    language: 'en',
  });

  await Patient.create({
    userId: user._id,
    doctorId,
    gender: pick(GENDERS),
    dateOfBirth: randomDob(),
    address: `${Math.floor(1 + Math.random() * 999)} ${pick(STREETS)}`,
    medicalHistory: 'No significant history',
  });
}

async function run() {
  const mongoUri = process.env.MONGODB_URI;
  if (!mongoUri) {
    throw new Error('MONGODB_URI is not set');
  }

  await mongoose.connect(mongoUri);

  for (const target of TARGETS) {
    const found = await getDoctorByEmails(target.emails);
    if (!found) {
      console.log(`[SKIP] ${target.label}: no matching doctor found for emails ${target.emails.join(', ')}`);
      continue;
    }

    const { user, doctor } = found;
    const existing = await Patient.countDocuments({ doctorId: doctor._id });
    const needed = Math.max(0, TARGET_MIN_PATIENTS - existing);

    console.log(`[INFO] ${target.label}: ${user.email} -> existing patients ${existing}, creating ${needed}`);

    for (let i = 0; i < needed; i++) {
      await createPatientForDoctor(String(doctor._id), target.label, i + 1);
    }

    const after = await Patient.countDocuments({ doctorId: doctor._id });
    console.log(`[DONE] ${target.label}: ${user.email} -> total patients ${after}`);
  }
}

run()
  .catch((error) => {
    console.error('[ERROR]', error);
    process.exitCode = 1;
  })
  .finally(async () => {
    await mongoose.disconnect();
  });
