import { NextResponse } from "next/server"
import { and, desc, eq, ne } from "drizzle-orm"
import { z } from "zod"
import { db } from "@/lib/db"
import { account_members, profiles } from "@/lib/db/schema"
import { getSessionUser } from "@/lib/session"
import { getAccountContext } from "@/lib/account"
import { PLAN_LIMITS } from "@/lib/stripe/plans"
import { sendEmail, teamInviteHtml } from "@/lib/email/send"
import type { Plan } from "@/types"

const inviteSchema = z.object({
  email: z.string().email("Enter a valid email address").max(254),
  role: z.enum(["member", "viewer"]).default("member"),
})

const APP_URL = process.env.NEXT_PUBLIC_APP_URL ?? "http://localhost:3000"

/**
 * GET — list the members the current OWNER has invited to their account.
 * Team management is always scoped to the real session user acting as owner
 * (never getEffectiveOwnerId), so a member can't manage the owner's team.
 */
export async function GET() {
  const user = await getSessionUser()
  if (!user) return NextResponse.json({ error: "Unauthorized" }, { status: 401 })

  const members = await db
    .select({
      id: account_members.id,
      email: account_members.email,
      role: account_members.role,
      status: account_members.status,
      member_id: account_members.member_id,
      accepted_at: account_members.accepted_at,
      created_at: account_members.created_at,
    })
    .from(account_members)
    .where(and(eq(account_members.owner_id, user.id), ne(account_members.status, "revoked")))
    .orderBy(desc(account_members.created_at))

  return NextResponse.json(members)
}

/**
 * POST — invite a user (by email) to the current owner's account. Gated to
 * plans with team access; only the account owner may invite.
 */
export async function POST(request: Request) {
  const user = await getSessionUser()
  if (!user) return NextResponse.json({ error: "Unauthorized" }, { status: 401 })

  // Only an account OWNER can manage a team — a member of someone else's
  // account must not be able to invite people into that account.
  const ctx = await getAccountContext(user.id)
  if (!ctx.isOwner) {
    return NextResponse.json(
      { error: "Only the account owner can manage the team" },
      { status: 403 }
    )
  }

  // Gate on the owner's plan.
  const profile = await db.query.profiles.findFirst({
    where: eq(profiles.id, user.id),
    columns: { plan: true, email: true },
  })
  const plan = (profile?.plan ?? "starter") as Plan
  if (!PLAN_LIMITS[plan].hasTeamAccess) {
    return NextResponse.json(
      { error: "Team access is available on the Landlord and Lifetime plans" },
      { status: 403 }
    )
  }

  const body = await request.json().catch(() => null)
  const parsed = inviteSchema.safeParse(body)
  if (!parsed.success) {
    return NextResponse.json(
      { error: parsed.error.issues[0]?.message ?? "Invalid input" },
      { status: 400 }
    )
  }

  const email = parsed.data.email.trim().toLowerCase()
  const { role } = parsed.data

  // Can't invite yourself.
  if (email === (profile?.email ?? user.email ?? "").toLowerCase()) {
    return NextResponse.json({ error: "You can't invite yourself" }, { status: 400 })
  }

  // Prevent a duplicate pending/active invite for the same email.
  const existing = await db.query.account_members.findFirst({
    where: and(eq(account_members.owner_id, user.id), eq(account_members.email, email)),
  })
  if (existing && (existing.status === "pending" || existing.status === "active")) {
    return NextResponse.json(
      {
        error:
          existing.status === "active"
            ? "That person is already a member of your account"
            : "An invite is already pending for that email",
      },
      { status: 409 }
    )
  }

  let inviteToken: string
  try {
    // Re-invite a previously revoked email by inserting a fresh pending row.
    const [row] = await db
      .insert(account_members)
      .values({ owner_id: user.id, email, role, status: "pending" })
      .returning({ invite_token: account_members.invite_token })
    inviteToken = row.invite_token
  } catch (e) {
    return NextResponse.json({ error: (e as Error).message }, { status: 500 })
  }

  const inviteUrl = `${APP_URL}/team/accept/${inviteToken}`
  const inviterName = profile?.email ?? user.email ?? "A landlord"

  await sendEmail({
    to: email,
    subject: "You've been invited to a Property Management Network account",
    html: teamInviteHtml({ inviterName, inviteUrl, role }),
  })

  return NextResponse.json({ ok: true })
}

