import { Billing } from "../src/billing.js"
import { and, Database, eq, isNull, sql } from "../src/drizzle/index.js"
import { UserTable } from "../src/schema/user.sql.js"
import { BillingTable, PaymentTable, SubscriptionTable } from "../src/schema/billing.sql.js"
import { Identifier } from "../src/identifier.js"
import { centsToMicroCents } from "../src/util/price.js"
import { AuthTable } from "../src/schema/auth.sql.js"

const workspaceID = process.argv[2]
const email = process.argv[3]

console.log(`Onboarding workspace ${workspaceID} for email ${email}`)

if (!workspaceID || !email) {
  console.error("Usage: bun foo.ts <workspaceID> <email>")
  process.exit(1)
}

// Look up the Stripe customer by email
const customers = await Billing.stripe().customers.list({ email, limit: 10, expand: ["data.subscriptions"] })
if (!customers.data) {
  console.error(`Error: No Stripe customer found for email ${email}`)
  process.exit(1)
}
const customer = customers.data.find((c) => c.subscriptions?.data[0]?.items.data[0]?.price.unit_amount === 20000)
if (!customer) {
  console.error(`Error: No Stripe customer found for email ${email} with $200 subscription`)
  process.exit(1)
}

const customerID = customer.id
const subscription = customer.subscriptions!.data[0]
const subscriptionID = subscription.id

// Validate the subscription is $200
const amountInCents = subscription.items.data[0]?.price.unit_amount ?? 0
if (amountInCents !== 20000) {
  console.error(`Error: Subscription amount is $${amountInCents / 100}, expected $200`)
  process.exit(1)
}

const subscriptionData = await Billing.stripe().subscriptions.retrieve(subscription.id, { expand: ["discounts"] })
const couponID =
  typeof subscriptionData.discounts[0] === "string"
    ? subscriptionData.discounts[0]
    : subscriptionData.discounts[0]?.coupon?.id

// Check if subscription is already tied to another workspace
const existingSubscription = await Database.use((tx) =>
  tx
    .select({ workspaceID: BillingTable.workspaceID })
    .from(BillingTable)
    .where(sql`JSON_EXTRACT(${BillingTable.subscription}, '$.id') = ${subscriptionID}`)
    .then((rows) => rows[0]),
)
if (existingSubscription) {
  console.error(
    `Error: Subscription ${subscriptionID} is already tied to workspace ${existingSubscription.workspaceID}`,
  )
  process.exit(1)
}

// Look up the workspace billing and check if it already has a customer id or subscription
const billing = await Database.use((tx) =>
  tx
    .select({ customerID: BillingTable.customerID, subscriptionID: BillingTable.subscriptionID })
    .from(BillingTable)
    .where(eq(BillingTable.workspaceID, workspaceID))
    .then((rows) => rows[0]),
)
if (billing?.subscriptionID) {
  console.error(`Error: Workspace ${workspaceID} already has a subscription: ${billing.subscriptionID}`)
  process.exit(1)
}
if (billing?.customerID) {
  console.warn(
    `Warning: Workspace ${workspaceID} already has a customer id: ${billing.customerID}, replacing with ${customerID}`,
  )
}

// Get the latest invoice and payment from the subscription
const invoices = await Billing.stripe().invoices.list({
  subscription: subscriptionID,
  limit: 1,
  expand: ["data.payments"],
})
const invoice = invoices.data[0]
const invoiceID = invoice?.id
const paymentID = invoice?.payments?.data[0]?.payment.payment_intent as string | undefined

// Get the default payment method from the customer
const paymentMethodID = (customer.invoice_settings.default_payment_method ?? subscription.default_payment_method) as
  | string
  | null
const paymentMethod = paymentMethodID ? await Billing.stripe().paymentMethods.retrieve(paymentMethodID) : null
const paymentMethodLast4 = paymentMethod?.card?.last4 ?? null
const paymentMethodType = paymentMethod?.type ?? null

// Look up the user in the workspace
const users = await Database.use((tx) =>
  tx
    .select({ id: UserTable.id, email: AuthTable.subject })
    .from(UserTable)
    .innerJoin(AuthTable, and(eq(AuthTable.accountID, UserTable.accountID), eq(AuthTable.provider, "email")))
    .where(and(eq(UserTable.workspaceID, workspaceID), isNull(UserTable.timeDeleted))),
)
if (users.length === 0) {
  console.error(`Error: No users found in workspace ${workspaceID}`)
  process.exit(1)
}
const user = users.length === 1 ? users[0] : users.find((u) => u.email === email)
if (!user) {
  console.error(`Error: User with email ${email} not found in workspace ${workspaceID}`)
  process.exit(1)
}

// Set workspaceID in Stripe customer metadata
await Billing.stripe().customers.update(customerID, {
  metadata: {
    workspaceID,
  },
})

await Database.transaction(async (tx) => {
  // Set customer id, subscription id, and payment method on workspace billing
  await tx
    .update(BillingTable)
    .set({
      customerID,
      subscriptionID,
      paymentMethodID,
      paymentMethodLast4,
      paymentMethodType,
      subscription: {
        status: "subscribed",
        coupon: couponID,
        seats: 1,
        plan: "200",
      },
    })
    .where(eq(BillingTable.workspaceID, workspaceID))

  // Create a row in subscription table
  await tx.insert(SubscriptionTable).values({
    workspaceID,
    id: Identifier.create("subscription"),
    userID: user.id,
  })

  // Create a row in payments table
  await tx.insert(PaymentTable).values({
    workspaceID,
    id: Identifier.create("payment"),
    amount: centsToMicroCents(amountInCents),
    customerID,
    invoiceID,
    paymentID,
    enrichment: {
      type: "subscription",
      couponID,
    },
  })
})

console.log(`Successfully onboarded workspace ${workspaceID}`)
console.log(`  Customer ID: ${customerID}`)
console.log(`  Subscription ID: ${subscriptionID}`)
console.log(
  `  Payment Method: ${paymentMethodID ?? "(none)"} (${paymentMethodType ?? "unknown"} ending in ${paymentMethodLast4 ?? "????"})`,
)
console.log(`  User ID: ${user.id}`)
console.log(`  Invoice ID: ${invoiceID ?? "(none)"}`)
console.log(`  Payment ID: ${paymentID ?? "(none)"}`)
