import * as crypto from 'node:crypto'
import * as fs from 'node:fs'

const GenMaxUInt = (max) => Math.floor(Math.random() * max)
const GenInt = (from, to) => Math.floor(Math.random() * (to - from) + from)

const male_full_name = [
  "Семенов Дмитрий Романович",
  "Захаров Сергей Григорьевич",
  "Панов Артём Маркович",
  "Исаев Владимир Елисеевич",
  "Кириллов Степан Дмитриевич",
  "Никитин Георгий Егорович",
  "Терехов Даниил Давидович",
  "Николаев Роман Артёмович",
  "Соболев Сергей Васильевич",
  "Афанасьев Серафим Тимофеевич",
]

const female_full_name = [
  "Макарова Виктория Глебовна",
  "Фролова Александра Владимировна",
  "Сычева Валерия Дмитриевна",
  "Плотникова Милана Марковна",
  "Носкова Таисия Тимуровна",
  "Чернышева Алиса Михайловна",
  "Михайлова Мария Яковлевна",
  "Никитина Ева Владимировна",
  "Лобанова Василиса Тимофеевна",
  "Князева Анна Данииловна",
]

function GenFullName() {
  const sex = GenMaxUInt(2) ? 'male' : 'female'


  let full_name

  if (sex == 'male') {
    full_name = male_full_name
  } else {
    full_name = female_full_name
  }
  const l = full_name.length
  const name_i = GenMaxUInt(l)
  const surname_i = GenMaxUInt(l)
  const middle_name_i = GenMaxUInt(l)
  const [name] = full_name[name_i].split(' ')
  const [, surname] = full_name[surname_i].split(' ')
  const [, , middle_name] = full_name[middle_name_i].split(' ')

  return `'${name} ${surname} ${middle_name}'`
}

const food_product_names = [
  'хлеб',
  'картофель',
  'яйца',
  'лук',
  'чеснок',
  'соль',
  'сахар',
  'масло',
  'макароны',
  'молоко',
]

const drug_names = [
  "парацетамол",
  "ибупрофен",
  "аспирин",
  "левомеколь",
  "активированный уголь",
  "но-шпа",
  "цитрамон",
  "лоратадин",
  "кагоцел",
  "амоксициллин",
]

const street_names = [
  "Улица Ленина",
  "Проспект Мира",
  "Улица Гагарина",
  "Набережная Реки Фонтанки",
  "Бульвар Космонавтов",
  "Переулок Строителей",
  "Проезд Шевченко",
  "Улица 8 Марта",
  "Микрорайон Солнечный",
  "Шоссе Энтузиастов",
]

function GenPassport() {
  let res = ''

  for (let i = 0; i < 10; i++) {
    res += GenMaxUInt(10)
  }
  return `'` + res.slice(0, 4) + ' ' + res.slice(4) + `'`
}

function GenAddress() {
  return `'` + street_names[GenMaxUInt(street_names.length)] + ' ' + GenMaxUInt(100) + `'`
}

function GenPasswdHash() {
  return `decode('${crypto.randomBytes(32).toString('base64')}', 'base64')`
}

function GenEmail() {
  return `'${GenMaxUInt(1000)}@mephi.ru'`
}

function GenPhone() {
  let res = `'+7`

  for (let i = 0; i < 10; i++) {
    res += GenMaxUInt(10)
  }
  return res + `'`
}

const billing = [
  'сбербанк',
  'тинкофф',
  'ипб',
]

function GenBillingAccount() {
  return `'${billing[GenMaxUInt(billing.length)]}'`
}

function GenTimestamp() {
  const start = new Date(2024, 0, 1).getTime()
  const end = new Date(2026, 0, 1).getTime()

  return `'${new Date(GenInt(start, end)).toISOString()}'`
}

function GenIntervalHours(max = 6) {
  return `'${GenInt(1, max)} hours'`
}

function GenPrice(max = 1000) {
  return (Math.random() * max + 10).toFixed(2)
}

const ClassTypes = ['Theory', 'Practice']
const RegistrationStatuses = ['NotPaid', 'Paid']
const UsageTypes = ['PayOnce', 'PayMonthly']

const COUNT = 10

function Values(callback, factor = 1) {
  let res = 'VALUES\n'
  const count = COUNT * factor

  for (let i = 0; i < count; i++) {
    res += callback()

    if (i == count - 1) {
      res += ';\n\n'
    } else {
      res += ',\n'
    }
  }
  return res
}

function Many(insert, callback) {
  let res = ''

  for (let i = 0; i < COUNT; i++) {
    res += insert + ' ' + callback() + ';\n'
  }
  return res + '\n'
}


// Person
let script = 'INSERT INTO "Person" (full_name, passwd_hash) ' + Values(() => {
  return `(${GenFullName()}, ${GenPasswdHash()})`
}, 2)

let person_id = 1

// Master
script += 'INSERT INTO "Master" ("Person_id", passport, readme) ' + Values(() => {
  return `(${person_id++}, ${GenPassport()}, 'aboba')`
})

// Client
script += 'INSERT INTO "Client" ("Person_id", phone, email, billing_account) ' + Values(() => {
  return `(${person_id++}, ${GenPhone()}, ${GenEmail()}, ${GenBillingAccount()})`
})

// Studio
script += 'INSERT INTO "Studio" (address, capacity, begin_date, duration, usage_price, usage_type) ' + Values(() => {
  return `(${GenAddress()}, ${GenInt(10, 80)}, ${GenTimestamp()}, ${GenIntervalHours(12)}, ${GenPrice(300)}, '${UsageTypes[GenMaxUInt(UsageTypes.length)]}')`
})

// Course
script += 'INSERT INTO "Course" ("Master_id", name, price, deadline_date) ' + Values(() => {
  return `(${GenInt(1, COUNT + 1)}, 'курс ${GenMaxUInt(3)}', ${GenPrice()}, ${GenTimestamp()})`
})

// Class
script += 'INSERT INTO "Class" (begin_date, "Course_id", "Studio_id", name, type, duration) ' + Values(() => {
  return `(${GenTimestamp()}, ${GenInt(1, COUNT + 1)}, ${GenInt(1, COUNT + 1)}, 'занятие ${GenMaxUInt(100)}', '${ClassTypes[GenMaxUInt(ClassTypes.length)]}', ${GenIntervalHours()})`
})

// Class_Master
script += Many(`INSERT INTO "Class_Master" ("Class_begin_date", "Class_Course_id", "Master_id")`, () => {
  return `SELECT begin_date, "Course_id", ${GenInt(1, COUNT + 1)} FROM "Class" LIMIT 1 OFFSET ${GenInt(0, COUNT)}`
})

// Registration
script += 'INSERT INTO "Registration" ("Client_id", "Course_id", date, status) ' + Values(() => {
  return `(${GenInt(COUNT + 1, COUNT * 2 + 1)}, ${GenInt(1, COUNT + 1)}, ${GenTimestamp()}, 'Paid')`
}, 0.5)

// FoodProductEnum
script += 'INSERT INTO "FoodProductEnum" (name, avg_price) ' + Values(() => {
  return `('${food_product_names[GenMaxUInt(food_product_names.length)]}', ${GenPrice(200)})`
})

// FoodProduct
script += Many(`INSERT INTO "FoodProduct" ("FoodProductEnum_id", "Class_begin_date", "Class_Course_id", buy_price, buy_date, delivery_price, delivery_date, expires_date)`, () => {
  return `SELECT ${GenInt(1, COUNT + 1)}, begin_date, "Course_id", ${GenPrice()}, ${GenTimestamp()}, ${GenPrice()}, ${GenTimestamp()}, ${GenTimestamp()} FROM "Class" LIMIT 1 OFFSET ${GenInt(0, COUNT)}`
})

// Equipment
script += 'INSERT INTO "Equipment" ("Studio_id", name, usage_price, usage_type, delivery_price, delivery_date) ' + Values(() => {
  return `(${GenInt(1, COUNT + 1)}, 'оборудование ${GenMaxUInt(100)}', ${GenPrice(300)}, '${UsageTypes[GenMaxUInt(UsageTypes.length)]}', ${GenPrice(200)}, ${GenTimestamp()})`
})

// Class_Equipment
script += Many(`INSERT INTO "Class_Equipment" ("Class_begin_date", "Class_Course_id", "Equipment_id")`, () => {
  return `SELECT begin_date, "Course_id", ${GenInt(1, COUNT + 1)} FROM "Class" LIMIT 1 OFFSET ${GenInt(0, COUNT)}`
})

// DrugEnum
script += 'INSERT INTO "DrugEnum" (name, avg_price) ' + Values(() => {
  return `('${drug_names[GenMaxUInt(drug_names.length)]}', ${GenPrice(500)})`
})

// Drug
script += 'INSERT INTO "Drug" ("DrugEnum_id", "Course_id", buy_price, buy_date, delivery_price, delivery_date, expires_date) ' + Values(() => {
  return `(${GenInt(1, COUNT + 1)}, ${GenInt(1, COUNT + 1)}, ${GenPrice()}, ${GenTimestamp()}, ${GenPrice()}, ${GenTimestamp()}, ${GenTimestamp()})`
})

// DrugIntolerance
script += 'INSERT INTO "DrugIntolerance" ("Person_id", "DrugEnum_id") ' + Values(() => {
  return `(${GenInt(1, COUNT * 2 + 1)}, ${GenInt(1, COUNT + 1)})`
})

// ActivityLog
script += 'INSERT INTO "ActivityLog" ("Person_id", action) ' + Values(() => {
  return `(${GenInt(1, COUNT * 2 + 1)}, 'login')`
})

const tables = [
  'Person',
  'Client',
  'Master',
  'Studio',
  'Course',
  'Class',
  'Class_Master',
  'Registration',
  'FoodProductEnum',
  'FoodProduct',
  'Equipment',
  'Class_Equipment',
  'DrugEnum',
  'Drug',
  'DrugIntolerance',
  'ActivityLog'
]

for (const table of tables) {
  script += `SELECT * FROM "${table}";\n`
}

fs.writeFileSync('data.sql', script)
