import { prisma } from '../../lib/prisma'

const companyListInclude = {
  brand: { select: { displayName: true, logoUrl: true, subdomain: true } },
  contractSettings: { select: { legalName: true } },
  subscription: { select: { plan: true, status: true } },
  _count: { select: { employees: true, vehicles: true } },
} as const

const companyDetailInclude = {
  brand: true,
  contractSettings: true,
  accountingSettings: true,
  subscription: { include: { invoices: { orderBy: { createdAt: 'desc' }, take: 10 } } },
  employees: true,
  _count: { select: { employees: true, vehicles: true, customers: true, reservations: true } },
} as const

const billingInclude = {
  company: { select: { id: true, name: true, email: true, slug: true, status: true } },
  invoices: {
    select: { id: true, amount: true, currency: true, status: true, paidAt: true, createdAt: true },
    orderBy: { createdAt: 'desc' },
    take: 5,
  },
  _count: { select: { invoices: true } },
} as const

function parseOptionalDate(value?: string | null) {
  if (!value) return null
  return new Date(value)
}

export function findAdminByEmail(email: string) {
  return prisma.adminUser.findFirst({
    where: {
      email: {
        equals: email,
        mode: 'insensitive',
      },
    },
  })
}

export function findAdminByIdOrThrow(id: string) {
  return prisma.adminUser.findUniqueOrThrow({ where: { id } })
}

export function updateAdminLastLogin(id: string) {
  return prisma.adminUser.update({ where: { id }, data: { lastLoginAt: new Date() } })
}

export function updateAdminTotpSecret(id: string, secret: string) {
  return prisma.adminUser.update({ where: { id }, data: { totpSecret: secret } })
}

export function enableAdminTotp(id: string) {
  return prisma.adminUser.update({ where: { id }, data: { totpEnabled: true } })
}


export async function replaceAdminRecoveryCodes(adminUserId: string, codeHashes: string[]) {
  return prisma.$transaction(async (tx) => {
    await tx.adminRecoveryCode.deleteMany({ where: { adminUserId } })
    await tx.adminRecoveryCode.createMany({
      data: codeHashes.map((codeHash) => ({ adminUserId, codeHash })),
    })
  })
}

export function listUnusedAdminRecoveryCodes(adminUserId: string) {
  return prisma.adminRecoveryCode.findMany({
    where: { adminUserId, usedAt: null },
    select: { id: true, codeHash: true },
    orderBy: { createdAt: 'asc' },
  })
}

export function markAdminRecoveryCodeUsed(id: string) {
  return prisma.adminRecoveryCode.update({ where: { id }, data: { usedAt: new Date() } })
}

export function setAdminPasswordReset(id: string, token: string, expiresAt: Date) {
  return prisma.adminUser.update({
    where: { id },
    data: { passwordResetToken: token, passwordResetExpiresAt: expiresAt },
  })
}

export function findAdminByResetToken(token: string) {
  return prisma.adminUser.findFirst({
    where: {
      passwordResetToken: token,
      passwordResetExpiresAt: { gt: new Date() },
    },
  })
}

export function updateAdminPassword(id: string, passwordHash: string) {
  return prisma.adminUser.update({
    where: { id },
    data: {
      passwordHash,
      passwordResetToken: null,
      passwordResetExpiresAt: null,
    },
  })
}

export function createAuditLog(data: Record<string, unknown>) {
  return prisma.auditLog.create({ data: data as any })
}

export async function listCompaniesPage(query: { q?: string; status?: string; plan?: string; page: number; pageSize: number }) {
  const where: any = {}
  if (query.status) where.status = query.status
  if (query.q) {
    where.OR = [
      { name: { contains: query.q, mode: 'insensitive' } },
      { email: { contains: query.q, mode: 'insensitive' } },
      { slug: { contains: query.q, mode: 'insensitive' } },
    ]
  }
  if (query.plan) where.subscription = { plan: query.plan }

  const [data, total] = await Promise.all([
    prisma.company.findMany({
      where,
      include: companyListInclude,
      skip: (query.page - 1) * query.pageSize,
      take: query.pageSize,
      orderBy: { createdAt: 'desc' },
    }),
    prisma.company.count({ where }),
  ])

  return { data, total }
}

export function getCompanyDetail(id: string) {
  return prisma.company.findUniqueOrThrow({ where: { id }, include: companyDetailInclude })
}

export function getCompanyUpdateSnapshot(id: string) {
  return prisma.company.findUniqueOrThrow({
    where: { id },
    include: { brand: true, contractSettings: true, accountingSettings: true, subscription: true },
  })
}

export async function applyCompanyUpdate(
  id: string,
  body: any,
  current: {
    name: string
    slug: string
    address?: unknown
    brand?: { paymentMethodsEnabled?: any[] | null } | null
  },
) {
  return prisma.$transaction(async (tx: any) => {
    if (body.company) {
      const companyData = { ...body.company }
      if (companyData.address && typeof companyData.address === 'object' && !Array.isArray(companyData.address)) {
        const baseAddress = current.address && typeof current.address === 'object' && !Array.isArray(current.address)
          ? current.address as Record<string, unknown>
          : {}
        companyData.address = { ...baseAddress, ...companyData.address }
      }
      await tx.company.update({ where: { id }, data: companyData })
    }

    if (body.subscription) {
      const sub = body.subscription
      await tx.subscription.upsert({
        where: { companyId: id },
        update: {
          ...sub,
          trialStartAt: parseOptionalDate(sub.trialStartAt),
          trialEndAt: parseOptionalDate(sub.trialEndAt),
          currentPeriodStart: parseOptionalDate(sub.currentPeriodStart),
          currentPeriodEnd: parseOptionalDate(sub.currentPeriodEnd),
          cancelledAt: parseOptionalDate(sub.cancelledAt),
        },
        create: {
          companyId: id,
          plan: sub.plan ?? 'STARTER',
          billingPeriod: sub.billingPeriod ?? 'MONTHLY',
          status: sub.status ?? 'TRIALING',
          currency: sub.currency ?? 'MAD',
          trialStartAt: parseOptionalDate(sub.trialStartAt),
          trialEndAt: parseOptionalDate(sub.trialEndAt),
          currentPeriodStart: parseOptionalDate(sub.currentPeriodStart),
          currentPeriodEnd: parseOptionalDate(sub.currentPeriodEnd),
          cancelledAt: parseOptionalDate(sub.cancelledAt),
          cancelAtPeriodEnd: sub.cancelAtPeriodEnd ?? false,
        } as any,
      })
    }

    if (body.brand) {
      await tx.brandSettings.upsert({
        where: { companyId: id },
        update: body.brand,
        create: {
          companyId: id,
          displayName: body.brand.displayName ?? current.name,
          subdomain: body.brand.subdomain ?? current.slug,
          paymentMethodsEnabled: current.brand?.paymentMethodsEnabled ?? [],
          ...body.brand,
        } as any,
      })
    }

    if (body.contractSettings) {
      await tx.contractSettings.upsert({
        where: { companyId: id },
        update: body.contractSettings,
        create: { companyId: id, ...body.contractSettings } as any,
      })
    }

    if (body.accountingSettings) {
      await tx.accountingSettings.upsert({
        where: { companyId: id },
        update: body.accountingSettings,
        create: { companyId: id, ...body.accountingSettings } as any,
      })
    }

    return tx.company.findUniqueOrThrow({ where: { id }, include: companyDetailInclude })
  })
}

export function updateCompanyStatus(id: string, status: string) {
  return prisma.company.update({ where: { id }, data: { status: status as any } })
}

export function deleteCompany(id: string) {
  return prisma.company.delete({ where: { id } })
}

export function getCompanyForImpersonation(id: string) {
  return prisma.company.findUniqueOrThrow({
    where: { id },
    include: { employees: { where: { role: 'OWNER' } } },
  })
}

export async function listRentersPage(query: { q?: string; blocked?: string; page: number; pageSize: number }) {
  const where: any = {}
  if (query.blocked !== undefined) where.isActive = query.blocked === 'false'
  if (query.q) {
    where.OR = [
      { firstName: { contains: query.q, mode: 'insensitive' } },
      { email: { contains: query.q, mode: 'insensitive' } },
    ]
  }

  const [data, total] = await Promise.all([
    prisma.renter.findMany({
      where,
      select: {
        id: true,
        firstName: true,
        lastName: true,
        email: true,
        phone: true,
        isActive: true,
        createdAt: true,
        _count: { select: { reservations: true } },
      },
      skip: (query.page - 1) * query.pageSize,
      take: query.pageSize,
      orderBy: { createdAt: 'desc' },
    }),
    prisma.renter.count({ where }),
  ])

  return { data, total }
}

export function updateRenterActive(id: string, isActive: boolean) {
  return prisma.renter.update({ where: { id }, data: { isActive } })
}

export async function getPlatformMetricCounts() {
  const [
    totalCompanies,
    activeCompanies,
    trialingCompanies,
    suspendedCompanies,
    totalRenters,
    totalReservations,
  ] = await Promise.all([
    prisma.company.count(),
    prisma.company.count({ where: { status: 'ACTIVE' } }),
    prisma.company.count({ where: { status: 'TRIALING' } }),
    prisma.company.count({ where: { status: 'SUSPENDED' } }),
    prisma.renter.count(),
    prisma.reservation.count(),
  ])

  return {
    totalCompanies,
    activeCompanies,
    trialingCompanies,
    suspendedCompanies,
    totalRenters,
    totalReservations,
  }
}

export async function listAuditLogsPage(query: { adminId?: string; action?: string; companyId?: string; entityId?: string; page: number; pageSize: number }) {
  const where: any = {}
  if (query.adminId) where.adminUserId = query.adminId
  if (query.action) where.action = { contains: query.action }
  if (query.companyId) where.companyId = query.companyId
  if (query.entityId) where.resourceId = query.entityId

  const [data, total] = await Promise.all([
    prisma.auditLog.findMany({
      where,
      include: { adminUser: { select: { firstName: true, lastName: true, email: true } } },
      skip: (query.page - 1) * query.pageSize,
      take: query.pageSize,
      orderBy: { createdAt: 'desc' },
    }),
    prisma.auditLog.count({ where }),
  ])

  return { data, total }
}

export function listAdmins() {
  return prisma.adminUser.findMany({
    include: { permissions: true },
  })
}

export function createAdmin(data: {
  email: string
  firstName: string
  lastName: string
  role: string
  passwordHash: string
  permissions?: any[]
}) {
  return prisma.adminUser.create({
    data: {
      email: data.email,
      firstName: data.firstName,
      lastName: data.lastName,
      role: data.role as any,
      passwordHash: data.passwordHash,
      permissions: data.permissions ? { create: data.permissions } : undefined,
    },
    include: { permissions: true },
  })
}

export function updateAdminRole(id: string, role: string) {
  return prisma.adminUser.update({ where: { id }, data: { role: role as any } })
}

export function updateAdmin(
  id: string,
  data: {
    email?: string
    firstName?: string
    lastName?: string
    role?: string
    passwordHash?: string
    isActive?: boolean
  },
) {
  return prisma.adminUser.update({
    where: { id },
    data: {
      ...(data.email !== undefined ? { email: data.email } : {}),
      ...(data.firstName !== undefined ? { firstName: data.firstName } : {}),
      ...(data.lastName !== undefined ? { lastName: data.lastName } : {}),
      ...(data.role !== undefined ? { role: data.role as any } : {}),
      ...(data.passwordHash !== undefined ? { passwordHash: data.passwordHash } : {}),
      ...(data.isActive !== undefined ? { isActive: data.isActive } : {}),
    },
    include: { permissions: true },
  })
}

export async function replaceAdminPermissions(id: string, permissions: any[]) {
  await prisma.adminUser.findUniqueOrThrow({ where: { id } })
  await prisma.$transaction([
    prisma.adminPermission.deleteMany({ where: { adminUserId: id } }),
    prisma.adminPermission.createMany({
      data: permissions.map((permission) => ({
        adminUserId: id,
        resource: permission.resource,
        actions: permission.actions,
      })) as any,
    }),
  ])
  return prisma.adminUser.findUniqueOrThrow({ where: { id }, include: { permissions: true } })
}

export async function listBillingPage(query: { status?: string; plan?: string; page: number; pageSize: number }) {
  const where: any = {}
  if (query.status) where.status = query.status
  if (query.plan) where.plan = query.plan

  const [data, total] = await Promise.all([
    prisma.subscription.findMany({
      where,
      include: billingInclude,
      skip: (query.page - 1) * query.pageSize,
      take: query.pageSize,
      orderBy: { createdAt: 'desc' },
    }),
    prisma.subscription.count({ where }),
  ])

  return { data, total }
}

export function listActiveSubscriptionsForMrr() {
  return prisma.subscription.findMany({
    where: { status: { in: ['ACTIVE', 'TRIALING'] as any[] } },
    select: { plan: true, billingPeriod: true },
  })
}

export async function getBillingStatusCounts() {
  const [activeCount, trialingCount, pastDueCount, cancelledCount] = await Promise.all([
    prisma.subscription.count({ where: { status: 'ACTIVE' } }),
    prisma.subscription.count({ where: { status: 'TRIALING' } }),
    prisma.subscription.count({ where: { status: 'PAST_DUE' } }),
    prisma.subscription.count({ where: { status: 'CANCELLED' } }),
  ])

  return { activeCount, trialingCount, pastDueCount, cancelledCount }
}

export async function listCompanyInvoicesPage(companyId: string, query: { page: number; pageSize: number }) {
  const [data, total] = await Promise.all([
    prisma.subscriptionInvoice.findMany({
      where: { companyId },
      orderBy: { createdAt: 'desc' },
      skip: (query.page - 1) * query.pageSize,
      take: query.pageSize,
    }),
    prisma.subscriptionInvoice.count({ where: { companyId } }),
  ])

  return { data, total }
}

export function getInvoicePdfRecord(invoiceId: string) {
  return prisma.subscriptionInvoice.findUniqueOrThrow({
    where: { id: invoiceId },
    include: {
      company: { select: { name: true, email: true, phone: true, address: true } },
      subscription: {
        select: {
          plan: true,
          billingPeriod: true,
          currency: true,
          currentPeriodStart: true,
          currentPeriodEnd: true,
        },
      },
    },
  })
}

export function listPricingConfigs() {
  return prisma.pricingConfig.findMany({ orderBy: [{ plan: 'asc' }, { billingPeriod: 'asc' }] })
}

export function upsertPricingConfig(plan: string, billingPeriod: string, amount: number, updatedBy?: string) {
  return prisma.pricingConfig.upsert({
    where: { plan_billingPeriod: { plan, billingPeriod } },
    update: { amount, updatedBy },
    create: { id: `prc_${plan.toLowerCase()}_${billingPeriod.toLowerCase()}`, plan, billingPeriod, amount, updatedBy },
  })
}

export function listPlanFeatures() {
  return prisma.planFeature.findMany({
    orderBy: [{ plan: 'asc' }, { sortOrder: 'asc' }, { createdAt: 'asc' }],
  })
}

export function createPlanFeature(data: { plan: 'STARTER' | 'GROWTH' | 'PRO'; label: string; sortOrder?: number }) {
  return prisma.planFeature.create({
    data: {
      plan: data.plan,
      label: data.label,
      sortOrder: data.sortOrder ?? 0,
    },
  })
}

export function updatePlanFeature(id: string, data: Partial<{ plan: 'STARTER' | 'GROWTH' | 'PRO'; label: string; sortOrder: number }>) {
  return prisma.planFeature.update({
    where: { id },
    data,
  })
}

export function deletePlanFeature(id: string) {
  return prisma.planFeature.delete({ where: { id } })
}

// ─── Pricing promotions ────────────────────────────────────────────────────

export function listPromotions() {
  return (prisma as any).pricingPromotion.findMany({ orderBy: { createdAt: 'desc' } })
}

export function createPromotion(data: {
  code: string; name: string; description?: string | null
  discountType: string; discountValue: number
  plans: string[]; periods: string[]
  maxUses?: number | null; validFrom: string; validUntil?: string | null
  isActive: boolean; createdBy?: string | null
}) {
  return (prisma as any).pricingPromotion.create({
    data: {
      ...data,
      validFrom: new Date(data.validFrom),
      validUntil: data.validUntil ? new Date(data.validUntil) : null,
    },
  })
}

export function updatePromotion(id: string, data: Partial<{
  code: string; name: string; description: string | null
  discountType: string; discountValue: number
  plans: string[]; periods: string[]
  maxUses: number | null; validFrom: string; validUntil: string | null
  isActive: boolean
}>) {
  const { validFrom, validUntil, ...rest } = data
  return (prisma as any).pricingPromotion.update({
    where: { id },
    data: {
      ...rest,
      ...(validFrom  ? { validFrom:  new Date(validFrom)  } : {}),
      ...(validUntil !== undefined ? { validUntil: validUntil ? new Date(validUntil) : null } : {}),
    },
  })
}

export function deletePromotion(id: string) {
  return (prisma as any).pricingPromotion.delete({ where: { id } })
}

export async function listNotificationsPage(query: {
  channel?: string
  status?: string
  companyId?: string
  page: number
  pageSize: number
}) {
  const where: any = {}
  if (query.channel)   where.channel   = query.channel
  if (query.status)    where.status    = query.status
  if (query.companyId) where.companyId = query.companyId

  const [data, total] = await Promise.all([
    prisma.notification.findMany({
      where,
      orderBy: { createdAt: 'desc' },
      skip: (query.page - 1) * query.pageSize,
      take: query.pageSize,
      include: { company: { select: { name: true } } },
    }),
    prisma.notification.count({ where }),
  ])
  return { data, total }
}
