import crypto from 'crypto'
import { EmployeeRole } from '@rentaldrivego/database'
import { prisma } from '../lib/prisma'
import { sendTransactionalEmail } from './notificationService'
import { coerceNotificationLocale } from './notificationLocalizationService'

const INVITE_TOKEN_TTL_MINUTES = 60 * 24 * 7

export interface InvitePayload {
  firstName: string
  lastName: string
  email: string
  role: EmployeeRole
}

export interface TeamMember {
  id: string
  clerkUserId: string
  firstName: string
  lastName: string
  email: string
  phone: string | null
  role: EmployeeRole
  isActive: boolean
  createdAt: Date
  updatedAt: Date
  lastActiveAt?: Date | null
  invitationStatus?: 'accepted' | 'pending' | 'revoked'
}

function ensureDashboardBasePath(baseUrl: string) {
  try {
    const url = new URL(baseUrl)
    const pathname = url.pathname.replace(/\/$/, '')
    if (!pathname.endsWith('/dashboard')) url.pathname = `${pathname}/dashboard`
    return url.toString().replace(/\/$/, '')
  } catch {
    const trimmed = baseUrl.replace(/\/$/, '')
    return trimmed.endsWith('/dashboard') ? trimmed : `${trimmed}/dashboard`
  }
}

function buildInviteEmail(
  resetUrl: string,
  companyName: string,
  firstName: string,
  role: EmployeeRole,
  locale: ReturnType<typeof coerceNotificationLocale>,
) {
  const greetingName = firstName.trim() || 'there'

  if (locale === 'fr') {
    return {
      subject: `Vous avez ete invite chez ${companyName}`,
      html: `
        <p>Bonjour ${greetingName},</p>
        <p>Vous avez ete invite a rejoindre ${companyName} sur RentalDriveGo en tant que ${role.toLowerCase()}.</p>
        <p><a href="${resetUrl}" style="background:#1d4ed8;color:#fff;padding:12px 24px;border-radius:8px;text-decoration:none;display:inline-block;font-weight:600;">Definir votre mot de passe</a></p>
        <p>Ce lien d'invitation expire dans 7 jours.</p>
        <p>RentalDriveGo</p>
      `,
      text: `Bonjour ${greetingName},\n\nVous avez ete invite a rejoindre ${companyName} sur RentalDriveGo en tant que ${role.toLowerCase()}.\n\nDefinissez votre mot de passe ici : ${resetUrl}\n\nCe lien d'invitation expire dans 7 jours.\n\nRentalDriveGo`,
    }
  }

  if (locale === 'ar') {
    return {
      subject: `تمت دعوتك إلى ${companyName}`,
      html: `
        <div dir="rtl" style="text-align:right">
          <p>مرحباً ${greetingName}،</p>
          <p>تمت دعوتك للانضمام إلى ${companyName} على RentalDriveGo بصفتك ${role.toLowerCase()}.</p>
          <p><a href="${resetUrl}" style="background:#1d4ed8;color:#fff;padding:12px 24px;border-radius:8px;text-decoration:none;display:inline-block;font-weight:600;">عيّن كلمة المرور</a></p>
          <p>تنتهي صلاحية رابط الدعوة هذا خلال 7 أيام.</p>
          <p>RentalDriveGo</p>
        </div>
      `,
      text: `مرحباً ${greetingName}،\n\nتمت دعوتك للانضمام إلى ${companyName} على RentalDriveGo بصفتك ${role.toLowerCase()}.\n\nعيّن كلمة المرور هنا: ${resetUrl}\n\nتنتهي صلاحية رابط الدعوة هذا خلال 7 أيام.\n\nRentalDriveGo`,
    }
  }

  return {
    subject: `You have been invited to ${companyName}`,
    html: `
      <p>Hi ${greetingName},</p>
      <p>You were invited to join ${companyName} on RentalDriveGo as a ${role.toLowerCase()}.</p>
      <p><a href="${resetUrl}" style="background:#1d4ed8;color:#fff;padding:12px 24px;border-radius:8px;text-decoration:none;display:inline-block;font-weight:600;">Set your password</a></p>
      <p>This invitation link expires in 7 days.</p>
      <p>RentalDriveGo</p>
    `,
    text: `Hi ${greetingName},\n\nYou were invited to join ${companyName} on RentalDriveGo as a ${role.toLowerCase()}.\n\nSet your password here: ${resetUrl}\n\nThis invitation link expires in 7 days.\n\nRentalDriveGo`,
  }
}

export async function listEmployees(companyId: string): Promise<TeamMember[]> {
  const employees = await prisma.employee.findMany({
    where: { companyId },
    orderBy: [{ role: 'asc' }, { createdAt: 'asc' }],
  })

  return employees.map((employee: any) => ({
    ...employee,
    lastActiveAt: null,
    invitationStatus: employee.passwordHash ? 'accepted' : 'pending',
  }))
}

export async function inviteEmployee(companyId: string, inviterId: string, payload: InvitePayload) {
  if (payload.role === 'OWNER') {
    throw Object.assign(new Error('Cannot invite a member with the OWNER role'), { statusCode: 400, code: 'invalid_role' })
  }

  const existing = await prisma.employee.findFirst({ where: { companyId, email: payload.email } })
  if (existing) {
    throw Object.assign(new Error('An employee with this email already exists in your team'), { statusCode: 409, code: 'employee_already_exists' })
  }

  const company = await prisma.company.findUniqueOrThrow({
    where: { id: companyId },
    include: { brand: { select: { defaultLocale: true, displayName: true } } },
  })
  const rawToken = crypto.randomBytes(32).toString('hex')
  const expiresAt = new Date(Date.now() + INVITE_TOKEN_TTL_MINUTES * 60 * 1000)
  const locale = coerceNotificationLocale(company.brand?.defaultLocale)

  const employee = await prisma.employee.create({
    data: {
      companyId,
      clerkUserId: `local_member_${crypto.randomUUID()}`,
      firstName: payload.firstName,
      lastName: payload.lastName,
      email: payload.email,
      role: payload.role,
      isActive: true,
      preferredLanguage: locale,
      passwordResetToken: rawToken,
      passwordResetExpiresAt: expiresAt,
    },
  })

  const dashboardUrl = ensureDashboardBasePath(
    process.env.DASHBOARD_URL ?? process.env.NEXT_PUBLIC_DASHBOARD_URL ?? 'http://localhost:3000/dashboard',
  )
  const resetUrl = `${dashboardUrl}/reset-password?token=${rawToken}`
  const message = buildInviteEmail(
    resetUrl,
    company.brand?.displayName ?? company.name,
    payload.firstName,
    payload.role,
    locale,
  )

  await sendTransactionalEmail({
    to: payload.email,
    subject: message.subject,
    html: message.html,
    text: message.text,
  })

  return {
    employee: {
      ...employee,
      lastActiveAt: null,
      invitationStatus: 'pending' as const,
    },
    invitationId: employee.id,
    invitedBy: inviterId,
  }
}

export async function updateEmployeeRole(companyId: string, requesterId: string, requesterRole: EmployeeRole, employeeId: string, payload: { role: EmployeeRole }) {
  const target = await prisma.employee.findFirstOrThrow({ where: { id: employeeId, companyId } })

  if (requesterRole !== 'OWNER') throw Object.assign(new Error('Only the account owner can change team member roles'), { statusCode: 403, code: 'forbidden' })
  if (target.role === 'OWNER') throw Object.assign(new Error('Cannot change the role of the account owner'), { statusCode: 400 })
  if (payload.role === 'OWNER') throw Object.assign(new Error('Cannot assign the OWNER role via this endpoint'), { statusCode: 400 })
  if (target.id === requesterId) throw Object.assign(new Error('You cannot change your own role'), { statusCode: 400 })

  return prisma.employee.update({ where: { id: employeeId }, data: { role: payload.role } })
}

export async function deactivateEmployee(companyId: string, requesterRole: EmployeeRole, employeeId: string) {
  if (requesterRole !== 'OWNER') throw Object.assign(new Error('Only the account owner can deactivate team members'), { statusCode: 403 })
  const target = await prisma.employee.findFirstOrThrow({ where: { id: employeeId, companyId } })
  if (target.role === 'OWNER') throw Object.assign(new Error('Cannot deactivate the account owner'), { statusCode: 400 })

  return prisma.employee.update({ where: { id: employeeId }, data: { isActive: false } })
}

export async function reactivateEmployee(companyId: string, requesterRole: EmployeeRole, employeeId: string) {
  if (requesterRole !== 'OWNER') throw Object.assign(new Error('Only the account owner can reactivate team members'), { statusCode: 403 })
  await prisma.employee.findFirstOrThrow({ where: { id: employeeId, companyId } })

  return prisma.employee.update({ where: { id: employeeId }, data: { isActive: true } })
}

export async function removeEmployee(companyId: string, requesterRole: EmployeeRole, employeeId: string) {
  if (requesterRole !== 'OWNER') throw Object.assign(new Error('Only the account owner can remove team members'), { statusCode: 403 })
  const target = await prisma.employee.findFirstOrThrow({ where: { id: employeeId, companyId } })
  if (target.role === 'OWNER') throw Object.assign(new Error('Cannot remove the account owner'), { statusCode: 400 })

  await prisma.employee.delete({ where: { id: employeeId } })
  return { success: true }
}
