import {fakerNL_BE} from '@faker-js/faker'
import type {SexType} from '@faker-js/faker'
import type {Prisma, PrismaClient, Meeting, Tag, User} from '@/generated/prisma/client'
import {Role} from '@/generated/prisma/client'
import {hashPassword} from '@/lib/passwordUtils'

export const seedDev = async (prisma: PrismaClient) => {
  const [user, admin] = await prisma.user.createManyAndReturn({
    data: [
      {
        email: 'test@example.com',
        username: 'Demo user',
        password: hashPassword('Test123Test'),
      },
      {
        email: 'admin@example.com',
        username: 'Admin user',
        password: hashPassword('Test123Test'),
        role: Role.Admin,
      },
    ],
  })

  await Promise.all([createContactInfoForUser(prisma, user), createContactInfoForUser(prisma, admin)])
}

async function createContactInfoForUser(prisma: PrismaClient, user: User) {
  const contacts: Prisma.ContactCreateManyInput[] = []

  for (let i = 0; i < 20; i++) {
    const sex = fakerNL_BE.person.sex() as SexType
    const firstName = fakerNL_BE.person.firstName(sex)
    const lastName = fakerNL_BE.datatype.boolean() ? fakerNL_BE.person.lastName(sex) : null
    const description = fakerNL_BE.lorem.sentence()

    const contactInfoMap: Record<string, () => string> = {
      email: () => fakerNL_BE.internet.email({firstName: firstName, lastName: lastName ?? undefined}),
      phone: () => fakerNL_BE.phone.number(),
      address: () =>
        fakerNL_BE.location.streetAddress() + ' ' + fakerNL_BE.location.zipCode() + ' ' + fakerNL_BE.location.city(),
      'work phone': () => fakerNL_BE.phone.number(),
      'work email': () => fakerNL_BE.internet.email({firstName: firstName, lastName: lastName ?? undefined}),
      'work place': () => fakerNL_BE.company.name(),
      'job title': () => fakerNL_BE.person.jobTitle(),
    }

    contacts.push({
      id: fakerNL_BE.string.uuid(),
      firstName,
      lastName,
      description,
      avatar: `/avatars/${sex}/AV${sex === 'female' ? fakerNL_BE.number.int({min: 51, max: 100}) : fakerNL_BE.number.int({min: 1, max: 50})}.png`,
      contactInfo: Object.keys(contactInfoMap)
        .filter(() => fakerNL_BE.datatype.boolean())
        .map(k => ({type: k, value: contactInfoMap[k]()})),
      favorite: i % 5 === 0,
      userId: user.id,
    })
  }

  const createdContacts = await prisma.contact.createManyAndReturn({
    data: contacts,
  })

  const createdTags: Promise<Tag>[] = []

  for (const name of ['Family', 'Friends', 'Work', 'School', 'Acquaintances']) {
    createdTags.push(
      prisma.tag.create({
        data: {
          name,
          userId: user.id,
          contacts: {
            connect: fakerNL_BE.helpers
              .arrayElements(createdContacts, fakerNL_BE.number.int({min: 0, max: 4}))
              .map(contact => ({id: contact.id})),
          },
        },
      }),
    )
  }

  const createdMeetings: Promise<Meeting>[] = []

  for (let i = 0; i < 10; i++) {
    const date = fakerNL_BE.date.future()
    createdMeetings.push(
      prisma.meeting.create({
        data: {
          id: fakerNL_BE.string.uuid(),
          title: fakerNL_BE.lorem.sentence(),
          description: fakerNL_BE.lorem.paragraph(),
          date: date,
          contactId: fakerNL_BE.helpers.arrayElement(createdContacts).id,
          userId: user.id,
        },
      }),
    )
  }

  await Promise.all([...createdTags, ...createdMeetings])
}
