import { NextResponse } from "next/server"
import { requireUser, isStaff } from "@/server/auth"
import { prisma } from "@/server/db"
import { activitySearch } from "@/server/smtp2go"
import { cnpjMatches } from "@/server/cnpj"

const MAX_RANGE_DAYS_CLIENT = 31
const MAX_RANGE_DAYS_STAFF = 90

function readCsv(value: string | null) {
  if (!value) return []
  return value
    .split(",")
    .map((s) => s.trim())
    .filter(Boolean)
}

function readBool(value: string | null): boolean | undefined {
  if (!value) return undefined
  const v = value.trim().toLowerCase()
  if (v === "1" || v === "true" || v === "yes") return true
  if (v === "0" || v === "false" || v === "no") return false
  return undefined
}

function readNumber(value: unknown): number | null {
  const n = Number(value)
  return Number.isFinite(n) ? n : null
}

type CountParams = {
  start_date?: string
  end_date?: string
  search?: string
  search_email_id?: string
  search_subject?: string
  search_sender?: string
  search_recipient?: string
  search_usernames?: string[]
  subaccounts?: string[]
  event_types?: string[]
}

function validateRangeOrThrow(startDate?: string, endDate?: string, maxDays?: number) {
  if (!startDate || !endDate || !maxDays) return
  const start = new Date(startDate)
  const end = new Date(endDate)
  if (Number.isNaN(start.getTime()) || Number.isNaN(end.getTime())) {
    throw new Error("INVALID_DATE_RANGE")
  }
  if (end < start) {
    throw new Error("INVALID_DATE_RANGE")
  }
  const maxMs = maxDays * 24 * 60 * 60 * 1000
  if (end.getTime() - start.getTime() > maxMs) {
    throw new Error(`DATE_RANGE_LIMIT_EXCEEDED_${maxDays}`)
  }
}

export async function GET(req: Request) {
  try {
    const user = await requireUser()
    const url = new URL(req.url)
    const staff = isStaff(user.role)

    const startDate = url.searchParams.get("start_date") ?? undefined
    const endDate = url.searchParams.get("end_date") ?? undefined
    const search = url.searchParams.get("search") ?? undefined
    const searchEmailId = url.searchParams.get("search_email_id") ?? undefined
    const searchSubject = url.searchParams.get("search_subject") ?? undefined
    const searchSender = url.searchParams.get("search_sender") ?? undefined
    const searchRecipient = url.searchParams.get("search_recipient") ?? undefined
    const continueToken = url.searchParams.get("continue_token") ?? undefined
    const onlyLatest = readBool(url.searchParams.get("only_latest"))
    const onlyLatestBySent = readBool(url.searchParams.get("only_latest_by_sent"))
    const includeHeaders = readBool(url.searchParams.get("include_headers"))

    validateRangeOrThrow(startDate, endDate, staff ? MAX_RANGE_DAYS_STAFF : MAX_RANGE_DAYS_CLIENT)

    const parsedLimit = Number(url.searchParams.get("limit") ?? 100)
    const limit = Number.isFinite(parsedLimit) ? Math.max(1, Math.min(1000, parsedLimit)) : 100

    const requestedSubaccounts = [
      ...url.searchParams.getAll("subaccount_id"),
      ...readCsv(url.searchParams.get("subaccounts")),
    ].filter(Boolean)
    const searchUsernames = [
      ...url.searchParams.getAll("search_username"),
      ...readCsv(url.searchParams.get("search_usernames")),
    ].filter(Boolean)
    const eventTypes = [
      ...url.searchParams.getAll("event_type"),
      ...readCsv(url.searchParams.get("event_types")),
    ].filter(Boolean)

    let allowedSubaccounts: string[] | null = null

    if (!staff) {
      const cnpj = user.cnpj?.trim()
      if (!cnpj) {
        return NextResponse.json({ error: "FORBIDDEN_NO_CNPJ" }, { status: 403 })
      }

      const allMetas = await prisma.subaccountMeta.findMany({
        where: { cnpj: { not: null } },
        select: { subaccountId: true, cnpj: true },
      })
      const metas = allMetas.filter((m) => cnpjMatches(m.cnpj, cnpj))

      allowedSubaccounts = metas.map((m) => m.subaccountId)
      if (!allowedSubaccounts.length) {
        return NextResponse.json({
          events: [],
          count: 0,
          continueToken: null,
          filters: { startDate, endDate, subaccounts: [] },
        })
      }

      if (requestedSubaccounts.length) {
        const denied = requestedSubaccounts.find((id) => !allowedSubaccounts!.includes(id))
        if (denied) {
          return NextResponse.json({ error: "FORBIDDEN_SUBACCOUNT" }, { status: 403 })
        }
      }
    }

    const subaccounts = requestedSubaccounts.length
      ? requestedSubaccounts
      : allowedSubaccounts

    const baseParams: CountParams = {
      start_date: startDate,
      end_date: endDate,
      search,
      search_email_id: searchEmailId,
      search_subject: searchSubject,
      search_sender: searchSender,
      search_recipient: searchRecipient,
      search_usernames: searchUsernames.length ? searchUsernames : undefined,
      subaccounts: subaccounts?.length ? subaccounts : undefined,
      event_types: eventTypes.length ? eventTypes : undefined,
    }

    const data = await activitySearch({
      ...baseParams,
      limit,
      continue_token: continueToken,
      only_latest: onlyLatest,
      only_latest_by_sent: onlyLatestBySent,
      event_types: baseParams.event_types,
      include_headers: includeHeaders,
    })

    const raw = data as unknown as Record<string, unknown>
    const allEvents = Array.isArray(data.events) ? data.events : []
    const allowedSet = allowedSubaccounts?.length ? new Set(allowedSubaccounts) : null
    const events = allowedSet
      ? allEvents.filter((ev) => {
          const rec = ev as Record<string, unknown>
          const subId =
            String(
              rec.subaccount_id ??
                rec.subaccountId ??
                rec.subaccount ??
                rec.sub_account_id ??
                ""
            ).trim()
          return subId ? allowedSet.has(subId) : false
        })
      : allEvents
    const totalCandidates = [
      readNumber(raw.total_events),
      readNumber(data.count),
      readNumber(raw.matching_count),
      readNumber(raw.total_count),
      readNumber(raw.total),
      readNumber(raw.event_count),
    ].filter((v): v is number => v !== null)
    let total = totalCandidates.length ? Math.max(...totalCandidates) : events.length
    let totalIsExact = totalCandidates.length > 0
    if (allowedSet) {
      // For client scope, enforce totals from the filtered payload to avoid leaking broader counts.
      total = events.length
      totalIsExact = false
    }

    return NextResponse.json({
      events,
      count: total,
      totalIsExact,
      continueToken: data.continue_token ?? null,
      filters: {
        startDate,
        endDate,
        search,
        searchEmailId,
        searchSubject,
        searchSender,
        searchRecipient,
        subaccounts: subaccounts ?? [],
        searchUsernames,
        eventTypes,
        limit,
        onlyLatest,
        onlyLatestBySent,
        includeHeaders,
      },
    })
  } catch (e: unknown) {
    const msg = e instanceof Error ? e.message : String(e ?? "")
    const status =
      msg === "UNAUTHORIZED"
        ? 401
        : msg.startsWith("FORBIDDEN")
          ? 403
          : msg === "INVALID_DATE_RANGE" || msg.startsWith("DATE_RANGE_LIMIT_EXCEEDED_")
            ? 400
            : 500
    return NextResponse.json({ error: msg || "EMAIL_HISTORY_ERROR" }, { status })
  }
}
