"use client"

import * as React from "react"
import { useSession } from "next-auth/react"
import { useAbility } from "@/components/providers/ability-provider"
import { DealsDateRangeFilter } from "@/components/deals/deals-date-range-filter"
import {
  CompactFilterPopover,
  compactFilterSectionIsActive,
  formatCompactFilterCurrency,
  isCompactFilterRangeSection,
  type CompactFilterSection,
} from "@/components/shared/compact-filter-popover"
import {
  DEALS_FILTER_CLEAR_BUTTON_CLASS,
} from "@/components/deals/deals-filter-styles"
import { formatTeamLabelForUi } from "@/lib/deal-display"
import { buildHierarchicalTeamFilterOptions } from "@/lib/team-filter"
import {
  isAccountExecutiveRoleName,
  isBdrRoleName,
  isLeadsAssignedScopeRole,
  isUserTeamLead,
  showTeamScopeFiltersOnLeads,
  type PermissionSource,
} from "@/lib/permissions"
import { resolveTeamMemberFilterUserIds, resolveRosterUserIdsForTeamFilter, buildRosterScopedUserFilterOptions } from "@/lib/team-member-filter"
import { encodeDivisionFilter } from "@/lib/team-filter"
import { getApiEntityId } from "@/api/permissions/types"
import { pickRoleIdFromOrgRoles } from "@/components/deals/contributor-user-picker"
import {
  useGetLeadChannelsQuery,
  useGetProfileQuery,
  useGetRolesQuery,
  useGetServicesQuery,
  useGetTimelineIntentsQuery,
} from "@/api/endpoints"
import { useGetAllUsersQuery, type TeamUser } from "@/api/endpoints/teams-api"
import { useGetTeamsQuery } from "@/api/endpoints"
import { parseLocalYmd } from "@/lib/calendar-date"
import { cn } from "@/lib/utils"
import {
  Tooltip,
  TooltipContent,
  TooltipProvider,
  TooltipTrigger,
} from "@/components/ui/tooltip"

export type TasksDealFiltersState = {
  team: string | "all"
  divisionId: string | "all"
  leadOwnerId: string | "all"
  contributorUserId: string | "all"
  assignAeId: string | "all"
  assignBdrId: string | "all"
  serviceId: string | "all"
  leadChannelId: string | "all"
  timelineIntentId: string | "all"
  dateRange?: { from?: string; to?: string }
}

export const EMPTY_TASKS_DEAL_FILTERS: TasksDealFiltersState = {
  team: "all",
  divisionId: "all",
  leadOwnerId: "all",
  contributorUserId: "all",
  assignAeId: "all",
  assignBdrId: "all",
  serviceId: "all",
  leadChannelId: "all",
  timelineIntentId: "all",
}

function scopedId(value: string | "all" | undefined): string | undefined {
  if (!value || value === "all") return undefined
  return value
}

export function tasksDealFiltersToQueryParams(filters: TasksDealFiltersState) {
  return {
    team: scopedId(filters.team),
    divisionId: scopedId(filters.divisionId),
    userId: scopedId(filters.leadOwnerId),
    contributorUserId: scopedId(filters.contributorUserId),
    aeUserId: scopedId(filters.assignAeId),
    bdrUserId: scopedId(filters.assignBdrId),
    serviceId: scopedId(filters.serviceId),
    leadChannelId: scopedId(filters.leadChannelId),
    timelineIntentId: scopedId(filters.timelineIntentId),
    dateFrom: filters.dateRange?.from,
    dateTo: filters.dateRange?.to,
    dateField: "createdAt" as const,
  }
}

export function hasActiveTasksDealFilters(filters: TasksDealFiltersState): boolean {
  return (
    filters.team !== "all" ||
    filters.divisionId !== "all" ||
    filters.leadOwnerId !== "all" ||
    filters.contributorUserId !== "all" ||
    filters.assignAeId !== "all" ||
    filters.assignBdrId !== "all" ||
    filters.serviceId !== "all" ||
    filters.leadChannelId !== "all" ||
    filters.timelineIntentId !== "all" ||
    Boolean(filters.dateRange?.from)
  )
}

function normalizeRoleLabel(name?: string | null): string {
  return (name ?? "").trim().toLowerCase().replace(/\s+/g, " ")
}

function userMatchesAeAssignmentPool(user: TeamUser, aeRoleId?: string): boolean {
  if (aeRoleId && user.role?.id === aeRoleId) return true
  const role = normalizeRoleLabel(user.role?.name)
  if (!role) return false
  if (isAccountExecutiveRoleName(role)) return true
  if (role.includes("account executive")) return true
  return role === "ae" || role.endsWith(" ae") || role.startsWith("ae ")
}

function userMatchesBdrAssignmentPool(user: TeamUser, bdrRoleId?: string): boolean {
  if (bdrRoleId && user.role?.id === bdrRoleId) return true
  const role = normalizeRoleLabel(user.role?.name)
  if (!role) return false
  if (isBdrRoleName(role)) return true
  if (role.includes("business development")) return true
  return role === "bdr" || role.includes(" bdr") || role.startsWith("bdr ")
}

function buildAssigneeFilterOptions(
  users: TeamUser[],
  allLabel: string,
  match: (user: TeamUser) => boolean,
): { value: string; label: string }[] {
  const matched = users.filter(match)
  const pool = matched.length > 0 ? matched : users
  const sorted = [...pool].sort((a, b) =>
    (a.name || a.email || a.id).localeCompare(b.name || b.email || b.id),
  )
  return [
    { value: "all", label: allLabel },
    ...sorted.map((u) => ({
      value: u.id,
      label: u.name || u.email || u.id,
    })),
  ]
}

function FilterTooltip({
  label,
  children,
  className,
}: {
  label: string
  children: React.ReactNode
  className?: string
}) {
  return (
    <Tooltip>
      <TooltipTrigger asChild>
        <div className={cn("min-w-0", className)}>{children}</div>
      </TooltipTrigger>
      <TooltipContent side="bottom" sideOffset={6}>
        {label}
      </TooltipContent>
    </Tooltip>
  )
}

type Props = {
  value: TasksDealFiltersState
  onChange: (next: TasksDealFiltersState) => void
  permissionSource: PermissionSource | null | undefined
  triggerClassName: string
  contentClassName: string
  enabled?: boolean
}

export function TasksDealFilters({
  value,
  onChange,
  permissionSource,
  triggerClassName,
  contentClassName,
  enabled = true,
}: Props) {
  const patch = React.useCallback(
    (partial: Partial<TasksDealFiltersState>) => {
      onChange({ ...value, ...partial })
    },
    [onChange, value],
  )

  const { data: session } = useSession()
  const sessionUserId = getApiEntityId(
    (session as { backendUser?: { id?: string } } | null)?.backendUser,
  )
  const showLeadOwnerFilter = React.useMemo(
    () => !isLeadsAssignedScopeRole(permissionSource),
    [permissionSource],
  )
  const { data: teams = [] } = useGetTeamsQuery(undefined, { skip: !enabled })
  const showTeamMemberFilter = React.useMemo(
    () => !showLeadOwnerFilter && isUserTeamLead(permissionSource, teams),
    [showLeadOwnerFilter, permissionSource, teams],
  );
  const showTeamScopeFilters = React.useMemo(
    () => showTeamScopeFiltersOnLeads(permissionSource, teams),
    [permissionSource, teams],
  );
  const needsUserDirectory = showLeadOwnerFilter || showTeamMemberFilter
  const { data: profile } = useGetProfileQuery(undefined, {
    skip: !enabled || !showTeamMemberFilter || Boolean(sessionUserId),
  })
  const actorUserId = sessionUserId ?? getApiEntityId(profile)
  const { data: allUsers = [], isSuccess: allUsersLoaded } = useGetAllUsersQuery(
    undefined,
    { skip: !enabled || !needsUserDirectory },
  )
  const { data: orgRoles = [] } = useGetRolesQuery(undefined, {
    skip: !enabled || !showLeadOwnerFilter,
  })
  const { data: leadChannels = [] } = useGetLeadChannelsQuery(undefined, {
    skip: !enabled,
  })
  const { data: services = [] } = useGetServicesQuery(undefined, { skip: !enabled })
  const { data: timelineIntents = [] } = useGetTimelineIntentsQuery(undefined, {
    skip: !enabled,
  })

  const teamFilterOptions = React.useMemo(
    () =>
      buildHierarchicalTeamFilterOptions(teams, {
        includeDivisionOptions: false,
      }).map((option) => ({
        value: option.value,
        label:
          option.group === "team"
            ? formatTeamLabelForUi(option.label)
            : option.label,
      })),
    [teams],
  )

  const divisionFilterOptions = React.useMemo(() => {
    const byId = new Map<string, string>()
    for (const team of teams) {
      const id = team.divisionId ?? team.division?.id
      const name = team.division?.name
      if (id && name) byId.set(id, name)
    }
    return [
      { value: "all", label: "All Divisions" },
      ...[...byId.entries()]
        .sort((a, b) => a[1].localeCompare(b[1]))
        .map(([id, name]) => ({ value: id, label: name })),
    ]
  }, [teams])

  const serviceFilterOptions = React.useMemo(
    () => [
      { value: "all", label: "All Services" },
      ...services.map((service) => ({
        value: service.id,
        label: service.name,
      })),
    ],
    [services],
  )

  const leadChannelFilterOptions = React.useMemo(
    () => [
      { value: "all", label: "All Channels" },
      ...leadChannels.map((channel) => ({
        value: channel.id,
        label: channel.name,
      })),
    ],
    [leadChannels],
  )

  const timelineIntentFilterOptions = React.useMemo(
    () => [
      { value: "all", label: "All Timeline Intents" },
      ...timelineIntents.map((intent) => ({
        value: intent.id,
        label: intent.name,
      })),
    ],
    [timelineIntents],
  )

  const leadOwnerFilterOptions = React.useMemo(() => {
    const aeUsers = allUsers.filter((u) => isAccountExecutiveRoleName(u.role?.name))
    const sorted = [...aeUsers].sort((a, b) =>
      (a.name || a.email || a.id).localeCompare(b.name || b.email || b.id),
    )
    return [
      { value: "all", label: "All Lead Owners" },
      ...sorted.map((u) => ({
        value: u.id,
        label: u.name || u.email || u.id,
      })),
    ]
  }, [allUsers])

  const teamMemberFilterUserIds = React.useMemo(() => {
    if (!showTeamMemberFilter || !actorUserId) return []
    return resolveTeamMemberFilterUserIds(actorUserId, teams, value.team)
  }, [showTeamMemberFilter, actorUserId, teams, value.team])

  const teamMemberFilterOptions = React.useMemo(() => {
    const usersById = new Map(allUsers.map((u) => [u.id, u]))
    const sortedIds = teamMemberFilterUserIds
      .filter((id) => usersById.has(id))
      .sort((a, b) => {
        const userA = usersById.get(a)!
        const userB = usersById.get(b)!
        return (userA.name || userA.email || a).localeCompare(
          userB.name || userB.email || b,
        )
      })
    return [
      { value: "all", label: "All Team Members" },
      ...sortedIds.map((id) => {
        const user = usersById.get(id)!
        return {
          value: id,
          label: user.name || user.email || id,
        }
      }),
    ]
  }, [allUsers, teamMemberFilterUserIds])

  const aeRoleId = React.useMemo(
    () => pickRoleIdFromOrgRoles(orgRoles, ["ae", "account executive"]),
    [orgRoles],
  )
  const bdrRoleId = React.useMemo(
    () =>
      pickRoleIdFromOrgRoles(orgRoles, [
        "bdr",
        "business development",
        "business development representative",
      ]),
    [orgRoles],
  )

  const assignAeFilterOptions = React.useMemo(
    () =>
      buildAssigneeFilterOptions(allUsers, "All Assign AE", (u) =>
        userMatchesAeAssignmentPool(u, aeRoleId),
      ),
    [allUsers, aeRoleId],
  )

  const assignBdrFilterOptions = React.useMemo(
    () =>
      buildAssigneeFilterOptions(allUsers, "All Assign BDR", (u) =>
        userMatchesBdrAssignmentPool(u, bdrRoleId),
      ),
    [allUsers, bdrRoleId],
  )

  const dateRange = React.useMemo(() => {
    if (!value.dateRange?.from) return undefined
    const from = parseLocalYmd(value.dateRange.from)
    if (!from) return undefined
    return {
      from,
      to: parseLocalYmd(value.dateRange.to),
    }
  }, [value.dateRange])

  const dateRangeTooltipLabel = React.useMemo(() => {
    if (!dateRange?.from) return "Filter by date range"
    const fmt = (d: Date) =>
      d.toLocaleDateString("default", {
        month: "short",
        day: "numeric",
        year: "numeric",
      })
    if (dateRange.to) {
      return `Date range: ${fmt(dateRange.from)} – ${fmt(dateRange.to)}`
    }
    return `Date range: ${fmt(dateRange.from)}`
  }, [dateRange])

  const teamRosterUserIds = React.useMemo(() => {
    if (value.team !== "all") {
      return resolveRosterUserIdsForTeamFilter(teams, value.team)
    }
    if (value.divisionId !== "all") {
      return resolveRosterUserIdsForTeamFilter(
        teams,
        encodeDivisionFilter(value.divisionId),
      )
    }
    return null
  }, [teams, value.team, value.divisionId])

  const hasTeamScope = teamRosterUserIds !== null

  const teamScopeGroupLabel = React.useMemo(() => {
    if (value.team !== "all") {
      const slug = value.team.toLowerCase()
      const team = teams.find(
        (entry) => entry.name.toLowerCase().replace(/\s+/g, "-") === slug,
      )
      if (team) return formatTeamLabelForUi(team.name)
    }
    if (value.divisionId !== "all") {
      const match = divisionFilterOptions.find((o) => o.value === value.divisionId)
      if (match) return match.label
    }
    return "Team members"
  }, [value.team, value.divisionId, teams, divisionFilterOptions])

  const scopedTeamMemberOptions = React.useMemo(() => {
    if (!teamRosterUserIds) return teamMemberFilterOptions
    return buildRosterScopedUserFilterOptions(
      allUsers,
      teamRosterUserIds,
      "All Team Members",
    )
  }, [teamRosterUserIds, allUsers, teamMemberFilterOptions])

  const scopedLeadOwnerOptions = React.useMemo(() => {
    if (!teamRosterUserIds) return leadOwnerFilterOptions
    return buildRosterScopedUserFilterOptions(
      allUsers,
      teamRosterUserIds,
      "All Lead Owners",
      (user) => isAccountExecutiveRoleName(user.role?.name),
    )
  }, [teamRosterUserIds, allUsers, leadOwnerFilterOptions])

  const scopedAssignAeOptions = React.useMemo(() => {
    if (!teamRosterUserIds) return assignAeFilterOptions
    return buildRosterScopedUserFilterOptions(
      allUsers,
      teamRosterUserIds,
      "All Assign AE",
      (user) => userMatchesAeAssignmentPool(user, aeRoleId),
    )
  }, [teamRosterUserIds, allUsers, assignAeFilterOptions, aeRoleId])

  const scopedAssignBdrOptions = React.useMemo(() => {
    if (!teamRosterUserIds) return assignBdrFilterOptions
    return buildRosterScopedUserFilterOptions(
      allUsers,
      teamRosterUserIds,
      "All Assign BDR",
      (user) => userMatchesBdrAssignmentPool(user, bdrRoleId),
    )
  }, [teamRosterUserIds, allUsers, assignBdrFilterOptions, bdrRoleId])

  React.useEffect(() => {
    if (hasTeamScope) return
    const resets: Partial<TasksDealFiltersState> = {}
    if (value.leadOwnerId !== "all") resets.leadOwnerId = "all"
    if (value.assignAeId !== "all") resets.assignAeId = "all"
    if (value.assignBdrId !== "all") resets.assignBdrId = "all"
    if (showLeadOwnerFilter && value.contributorUserId !== "all") {
      resets.contributorUserId = "all"
    }
    if (Object.keys(resets).length > 0) patch(resets)
  }, [
    hasTeamScope,
    value.leadOwnerId,
    value.assignAeId,
    value.assignBdrId,
    value.contributorUserId,
    showLeadOwnerFilter,
    patch,
  ])

  const ability = useAbility()
  const canUpdateLead = ability.can("update", "lead")

  const compactFilterSections = React.useMemo((): CompactFilterSection[] => {
    const userLoading = needsUserDirectory && !allUsersLoaded
    const sections: CompactFilterSection[] = [
      {
        id: "timeline",
        label: "Timeline",
        value: value.timelineIntentId,
        options: timelineIntentFilterOptions,
        onValueChange: (v) => patch({ timelineIntentId: v }),
      },
    ]

    if (canUpdateLead && showTeamScopeFilters) {
      sections.push(
        {
          id: "team",
          label: "Team",
          value: value.team,
          options: teamFilterOptions,
          onValueChange: (v) => {
            patch({
              team: v,
              ...(v !== "all" ? { divisionId: "all" as const } : {}),
            })
          },
        },
        {
          id: "division",
          label: "Division",
          value: value.divisionId,
          options: divisionFilterOptions,
          onValueChange: (v) => {
            patch({
              divisionId: v,
              ...(v !== "all" ? { team: "all" as const } : {}),
            })
          },
        },
      )
    }

    if (hasTeamScope) {
      const peopleSectionBase = {
        group: teamScopeGroupLabel,
        disabled: userLoading,
        loading: userLoading,
      }

      if (showTeamMemberFilter || showLeadOwnerFilter) {
        sections.push({
          id: "team-member",
          label: "Team members",
          value: value.contributorUserId,
          options: scopedTeamMemberOptions,
          onValueChange: (v) => patch({ contributorUserId: v }),
          ...peopleSectionBase,
        })
      }

      if (showLeadOwnerFilter || showTeamMemberFilter) {
        sections.push(
          {
            id: "lead-owner",
            label: "Lead owners",
            value: value.leadOwnerId,
            options: scopedLeadOwnerOptions,
            onValueChange: (v) => patch({ leadOwnerId: v }),
            ...peopleSectionBase,
          },
          {
            id: "assign-ae",
            label: "Assigned AE",
            value: value.assignAeId,
            options: scopedAssignAeOptions,
            onValueChange: (v) => patch({ assignAeId: v }),
            ...peopleSectionBase,
          },
          {
            id: "assign-bdr",
            label: "Assigned BDR",
            value: value.assignBdrId,
            options: scopedAssignBdrOptions,
            onValueChange: (v) => patch({ assignBdrId: v }),
            ...peopleSectionBase,
          },
        )
      }
    } else if (showTeamMemberFilter) {
      sections.push({
        id: "team-member",
        label: "Team member",
        value: value.contributorUserId,
        options: teamMemberFilterOptions,
        onValueChange: (v) => patch({ contributorUserId: v }),
        disabled: userLoading && teamMemberFilterUserIds.length > 0,
        loading: userLoading && teamMemberFilterUserIds.length > 0,
      })
    }

    sections.push(
      {
        id: "service",
        label: "Service",
        value: value.serviceId,
        options: serviceFilterOptions,
        onValueChange: (v) => patch({ serviceId: v }),
      },
      {
        id: "channel",
        label: "Channel",
        value: value.leadChannelId,
        options: leadChannelFilterOptions,
        onValueChange: (v) => patch({ leadChannelId: v }),
      },
    )

    return sections
  }, [
    needsUserDirectory,
    allUsersLoaded,
    value,
    patch,
    timelineIntentFilterOptions,
    canUpdateLead,
    teamFilterOptions,
    divisionFilterOptions,
    hasTeamScope,
    teamScopeGroupLabel,
    scopedTeamMemberOptions,
    scopedLeadOwnerOptions,
    scopedAssignAeOptions,
    scopedAssignBdrOptions,
    showTeamMemberFilter,
    teamMemberFilterOptions,
    teamMemberFilterUserIds.length,
    showLeadOwnerFilter,
    serviceFilterOptions,
    leadChannelFilterOptions,
  ])

  const compactFiltersTooltip = React.useMemo(() => {
    const active = compactFilterSections
      .filter(compactFilterSectionIsActive)
      .map((section) => {
        if (isCompactFilterRangeSection(section)) {
          const lo = section.min ?? 0
          const hi = section.max ?? 1_000_000
          return `${section.label}: ${formatCompactFilterCurrency(lo)} – ${formatCompactFilterCurrency(hi)}`
        }
        if (section.multi) {
          return `${section.label}: ${section.values.join(", ")}`
        }
        const option = section.options.find((o) => o.value === section.value)
        return `${section.label}: ${option?.label ?? section.value}`
      })
    if (active.length === 0) return "Filters"
    return active.join(" · ")
  }, [compactFilterSections])

  return (
    <TooltipProvider delayDuration={300}>
      <div className="flex w-full items-center justify-end gap-2">
        <FilterTooltip label={compactFiltersTooltip} className="shrink-0">
          <CompactFilterPopover
            sections={compactFilterSections}
            triggerClassName={DEALS_FILTER_CLEAR_BUTTON_CLASS}
            contentClassName={contentClassName}
            ariaLabel="Deal filters"
          />
        </FilterTooltip>

        <FilterTooltip label={dateRangeTooltipLabel} className="shrink-0">
          <DealsDateRangeFilter
            dateRange={dateRange}
            onDateRangeChange={(range) => patch({ dateRange: range })}
          />
        </FilterTooltip>
      </div>
    </TooltipProvider>
  )
}
