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

// ─── Subscription queries ─────────────────────────────────────

export function findByCompany(companyId: string) {
  return prisma.subscription.findUnique({
    where: { companyId },
    include: {
      invoices: { orderBy: { createdAt: 'desc' }, take: 12 },
      events:   { orderBy: { occurredAt: 'desc' }, take: 20 },
    },
  })
}

export function findById(id: string) {
  return prisma.subscription.findUnique({
    where: { id },
    include: { company: true },
  })
}

export function findInvoices(companyId: string) {
  return prisma.subscriptionInvoice.findMany({
    where: { companyId },
    orderBy: { createdAt: 'desc' },
    take: 50,
  })
}

export function findInvoiceByAmanpay(transactionId: string) {
  return prisma.subscriptionInvoice.findFirst({
    where: { amanpayTransactionId: transactionId },
    include: { subscription: true },
  })
}

export function findInvoiceByPaypal(captureId: string) {
  return prisma.subscriptionInvoice.findFirst({
    where: { paypalCaptureId: captureId },
    include: { subscription: true },
  })
}

export function findInvoiceByPaypalForCompany(paypalOrderId: string, companyId: string) {
  return prisma.subscriptionInvoice.findFirstOrThrow({
    where: { paypalCaptureId: paypalOrderId, companyId },
    include: { subscription: true },
  })
}

export function findInvoiceById(id: string) {
  return prisma.subscriptionInvoice.findUniqueOrThrow({
    where: { id },
    include: { subscription: true },
  })
}

// ─── Subscription mutations ───────────────────────────────────

export async function findOrCreateSubscription(
  companyId: string,
  plan: string,
  billingPeriod: string,
  currency: string,
) {
  const existing = await prisma.subscription.findUnique({ where: { companyId } })
  if (existing) return existing
  return prisma.subscription.create({
    data: { companyId, plan: plan as any, billingPeriod: billingPeriod as any, currency, status: 'PAYMENT_PENDING' as any },
  })
}

export function activateSubscription(id: string, periodEnd: Date) {
  return prisma.subscription.update({
    where: { id },
    data: {
      status: 'ACTIVE',
      currentPeriodStart:  new Date(),
      currentPeriodEnd:    periodEnd,
      paymentPendingSince: null,
      paymentDueAt:        null,
      pastDueSince:        null,
      suspendedAt:         null,
      retryCount:          0,
    },
  })
}

export function startTrial(
  companyId: string,
  plan: string,
  billingPeriod: string,
  currency: string,
  trialEndAt: Date,
) {
  return prisma.subscription.upsert({
    where: { companyId },
    update: {
      plan:         plan as any,
      billingPeriod: billingPeriod as any,
      currency,
      status:       'TRIALING',
      trialStartAt: new Date(),
      trialEndAt,
      trialUsed:    true,
    },
    create: {
      companyId,
      plan:         plan as any,
      billingPeriod: billingPeriod as any,
      currency,
      status:       'TRIALING',
      trialStartAt: new Date(),
      trialEndAt,
      trialUsed:    true,
    },
  })
}

export function setPaymentPending(id: string) {
  const now = new Date()
  const dueAt = new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000)
  return prisma.subscription.update({
    where: { id },
    data: {
      status:              'PAYMENT_PENDING',
      paymentPendingSince: now,
      paymentDueAt:        dueAt,
    },
  })
}

export function setPastDue(id: string) {
  return prisma.subscription.update({
    where: { id },
    data: {
      status:       'PAST_DUE',
      pastDueSince: new Date(),
    },
  })
}

export function setSuspended(id: string) {
  return prisma.subscription.update({
    where: { id },
    data: {
      status:      'SUSPENDED',
      suspendedAt: new Date(),
    },
  })
}

export function setExpired(id: string) {
  return prisma.subscription.update({
    where: { id },
    data: { status: 'EXPIRED', endedAt: new Date() },
  })
}

export function setCancelled(id: string, immediate: boolean) {
  if (immediate) {
    return prisma.subscription.update({
      where: { id },
      data: { status: 'CANCELLED', cancelledAt: new Date(), endedAt: new Date() },
    })
  }
  return prisma.subscription.update({
    where: { id },
    data: { cancelAtPeriodEnd: true },
  })
}

export function setCancelAtPeriodEnd(companyId: string, value: boolean) {
  return prisma.subscription.update({
    where: { companyId },
    data: { cancelAtPeriodEnd: value },
  })
}

export function incrementRetryCount(id: string) {
  return prisma.subscription.update({
    where: { id },
    data: { retryCount: { increment: 1 } },
  })
}

export function updatePlan(companyId: string, data: { plan: any; billingPeriod: any; currency: string }) {
  return prisma.subscription.update({ where: { companyId }, data })
}

// ─── Invoice mutations ────────────────────────────────────────

export function createInvoice(data: {
  companyId: string
  subscriptionId: string
  amount: number
  currency: string
  paymentProvider: string
  amanpayTransactionId?: string | null
  paypalCaptureId?: string | null
  dueAt?: Date | null
}) {
  return prisma.subscriptionInvoice.create({
    data: { ...data, status: 'PENDING', paymentProvider: data.paymentProvider as any },
  })
}

export function markInvoicePaid(id: string) {
  return prisma.subscriptionInvoice.update({
    where: { id },
    data: { status: 'PAID', paidAt: new Date(), failedAt: null },
  })
}

export function markInvoiceFailed(id: string) {
  return prisma.subscriptionInvoice.update({
    where: { id },
    data: { status: 'FAILED', failedAt: new Date() },
  })
}

export function markInvoiceVoided(id: string) {
  return prisma.subscriptionInvoice.update({
    where: { id },
    data: { status: 'VOIDED', voidedAt: new Date() },
  })
}

export function updateInvoicePaypal(id: string, captureId: string) {
  return prisma.subscriptionInvoice.update({
    where: { id },
    data: { status: 'PAID', paidAt: new Date(), paypalCaptureId: captureId, failedAt: null },
  })
}

// ─── Payment attempts ─────────────────────────────────────────

export function createPaymentAttempt(data: {
  invoiceId: string
  subscriptionId: string
  providerPaymentId?: string | null
  status: string
  failureCode?: string | null
  failureMessage?: string | null
}) {
  return prisma.paymentAttempt.create({
    data: { ...data, attemptedAt: new Date() },
  })
}

export function getPaymentAttempts(invoiceId: string) {
  return prisma.paymentAttempt.findMany({
    where: { invoiceId },
    orderBy: { attemptedAt: 'desc' },
  })
}

// ─── Subscription events ──────────────────────────────────────

export function createEvent(data: {
  subscriptionId: string
  companyId: string
  eventType: string
  source?: string
  payload?: object
}) {
  return prisma.subscriptionEvent.create({
    data: {
      ...data,
      source:    data.source ?? 'system',
      payload:   (data.payload ?? {}) as any,
      occurredAt: new Date(),
    },
  })
}

export function getEvents(subscriptionId: string) {
  return prisma.subscriptionEvent.findMany({
    where: { subscriptionId },
    orderBy: { occurredAt: 'desc' },
    take: 50,
  })
}

// ─── Scheduled job helpers ────────────────────────────────────

export function findPaymentPendingTimedOut(cutoffDate: Date) {
  return prisma.subscription.findMany({
    where: {
      status: 'PAYMENT_PENDING',
      paymentPendingSince: { lte: cutoffDate },
    },
    include: { company: true },
  })
}

export function findPastDueTimedOut(cutoffDate: Date) {
  return prisma.subscription.findMany({
    where: {
      status: 'PAST_DUE',
      pastDueSince: { lte: cutoffDate },
    },
    include: { company: true },
  })
}

export function findSuspendedTimedOut(cutoffDate: Date) {
  return prisma.subscription.findMany({
    where: {
      status: 'SUSPENDED',
      suspendedAt: { lte: cutoffDate },
    },
    include: { company: true },
  })
}

export function findTrialsEndedWithoutConversion() {
  return prisma.subscription.findMany({
    where: {
      status: 'TRIALING',
      trialEndAt: { lte: new Date() },
    },
    include: { company: { include: { employees: { where: { role: 'OWNER' }, take: 1 } } } },
  })
}

export function findSubscriptionsToExpireAtPeriodEnd() {
  return prisma.subscription.findMany({
    where: {
      status: 'ACTIVE',
      cancelAtPeriodEnd: true,
      currentPeriodEnd: { lte: new Date() },
    },
    include: { company: true },
  })
}
