import { keepPreviousData } from '@tanstack/react-query'
import { useDebounce } from '@uidotdev/usehooks'
import dayjs from 'dayjs'
import { ArrowDown, ArrowUp, RefreshCw } from 'lucide-react'
import { useEffect, useMemo, useState } from 'react'
import { Button } from 'ui'
import { ShimmeringLoader } from 'ui-patterns/ShimmeringLoader'
import { TimestampInfo } from 'ui-patterns/TimestampInfo'

import { LogsDatePicker } from '../Settings/Logs/Logs.DatePickers'
import { filterByProjects, sortAuditLogs } from './AuditLogs.utils'
import { LogDetailsPanel } from '@/components/interfaces/AuditLogs/LogDetailsPanel'
import { ScaffoldContainer, ScaffoldSection } from '@/components/layouts/Scaffold'
import Table from '@/components/to-be-cleaned/Table'
import AlertError from '@/components/ui/AlertError'
import { ButtonTooltip } from '@/components/ui/ButtonTooltip'
import { FilterPopover } from '@/components/ui/FilterPopover'
import {
  TIMESTAMP_MICROS_PER_MS,
  type AuditLog,
} from '@/data/organizations/organization-audit-logs-query'
import { useOrganizationsQuery } from '@/data/organizations/organizations-query'
import { useProfileAuditLogsQuery } from '@/data/profile/profile-audit-logs-query'
import { useProjectsInfiniteQuery } from '@/data/projects/projects-infinite-query'

export const AuditLogs = () => {
  const currentTime = dayjs().utc().set('millisecond', 0)

  const [search, setSearch] = useState('')
  const debouncedSearch = useDebounce(search, 500)

  const [dateSortDesc, setDateSortDesc] = useState(true)
  const [dateRange, setDateRange] = useState({
    from: currentTime.subtract(1, 'day').toISOString(),
    to: currentTime.toISOString(),
  })

  const [selectedLog, setSelectedLog] = useState<AuditLog>()
  const [filters, setFilters] = useState<{ projects: string[] }>({
    projects: [],
  })

  const {
    data: projectsData,
    isLoading: isLoadingProjects,
    isFetching,
    isFetchingNextPage,
    hasNextPage,
    fetchNextPage,
  } = useProjectsInfiniteQuery(
    { search: search.length === 0 ? search : debouncedSearch },
    { placeholderData: keepPreviousData }
  )
  const projects =
    useMemo(() => projectsData?.pages.flatMap((page) => page.projects), [projectsData?.pages]) || []

  const { data: organizations } = useOrganizationsQuery()
  const {
    data,
    error,
    isPending: isLoading,
    isSuccess,
    isError,
    isRefetching,
    refetch,
  } = useProfileAuditLogsQuery(
    {
      iso_timestamp_start: dateRange.from,
      iso_timestamp_end: dateRange.to,
    },
    {
      retry: false,
    }
  )

  const logs = data?.result ?? []
  const sortedLogs = filterByProjects(sortAuditLogs(logs, dateSortDesc), filters.projects)

  // This feature depends on the subscription tier of the user. Free user can view logs up to 1 day
  // in the past. The API limits the logs to maximum of 1 day and 5 minutes so when the page is
  // viewed for more than 5 minutes, the call parameters needs to be updated. This also works with
  // higher tiers (7 days of logs).The user will see a loading shimmer.
  useEffect(() => {
    const duration = dayjs(dateRange.from).diff(dayjs(dateRange.to))
    const interval = setInterval(() => {
      const currentTime = dayjs().utc().set('millisecond', 0)
      setDateRange({
        from: currentTime.add(duration).toISOString(),
        to: currentTime.toISOString(),
      })
    }, 5 * 60000)

    return () => clearInterval(interval)
  }, [dateRange.from, dateRange.to])

  return (
    <>
      <ScaffoldContainer className="px-6 xl:px-10">
        <ScaffoldSection isFullWidth>
          <div className="space-y-4 flex flex-col">
            <div className="flex flex-col md:flex-row md:items-center justify-between">
              <div className="flex items-center space-x-2">
                <p className="text-xs prose">Filter by</p>
                <FilterPopover
                  name="Projects"
                  options={projects ?? []}
                  labelKey="name"
                  valueKey="ref"
                  activeOptions={filters.projects}
                  onSaveFilters={(values) => setFilters({ ...filters, projects: values })}
                  search={search}
                  setSearch={setSearch}
                  hasNextPage={hasNextPage}
                  isLoading={isLoadingProjects}
                  isFetching={isFetching}
                  isFetchingNextPage={isFetchingNextPage}
                  fetchNextPage={fetchNextPage}
                />
                <LogsDatePicker
                  hideWarnings
                  value={dateRange}
                  onSubmit={(value) => setDateRange(value)}
                  helpers={[
                    {
                      text: 'Last 1 hour',
                      calcFrom: () => dayjs().subtract(1, 'hour').toISOString(),
                      calcTo: () => dayjs().toISOString(),
                    },
                    {
                      text: 'Last 3 hours',
                      calcFrom: () => dayjs().subtract(3, 'hour').toISOString(),
                      calcTo: () => dayjs().toISOString(),
                    },

                    {
                      text: 'Last 6 hours',
                      calcFrom: () => dayjs().subtract(6, 'hour').toISOString(),
                      calcTo: () => dayjs().toISOString(),
                    },
                    {
                      text: 'Last 12 hours',
                      calcFrom: () => dayjs().subtract(12, 'hour').toISOString(),
                      calcTo: () => dayjs().toISOString(),
                    },
                    {
                      text: 'Last 24 hours',
                      calcFrom: () => dayjs().subtract(1, 'day').toISOString(),
                      calcTo: () => dayjs().toISOString(),
                    },
                  ]}
                />
                {isSuccess && (
                  <>
                    <div className="h-[20px] border-r border-strong !ml-4 !mr-2" />
                    <p className="prose text-xs">Viewing {sortedLogs.length} logs in total</p>
                  </>
                )}
              </div>
              <Button
                type="default"
                disabled={isLoading || isRefetching}
                icon={<RefreshCw className={isRefetching ? 'animate-spin' : ''} />}
                onClick={() => refetch()}
              >
                {isRefetching ? 'Refreshing' : 'Refresh'}
              </Button>
            </div>

            {isLoading && (
              <div className="space-y-2">
                <ShimmeringLoader />
                <ShimmeringLoader className="w-3/4" />
                <ShimmeringLoader className="w-1/2" />
              </div>
            )}

            {isError && <AlertError error={error} subject="Failed to retrieve audit logs" />}

            {isSuccess && (
              <>
                {logs.length === 0 ? (
                  <div className="bg-surface-100 border rounded-sm p-4 flex items-center justify-between">
                    <p className="prose text-sm">You do not have any audit logs available yet</p>
                  </div>
                ) : logs.length > 0 && sortedLogs.length === 0 ? (
                  <div className="bg-surface-100 border rounded-sm p-4 flex items-center justify-between">
                    <p className="prose text-sm">
                      No audit logs found based on the filters applied
                    </p>
                  </div>
                ) : (
                  <div className="overflow-hidden md:overflow-auto overflow-x-scroll">
                    <Table
                      head={[
                        <Table.th key="action" className="py-2">
                          Action
                        </Table.th>,
                        <Table.th key="target" className="py-2">
                          Target
                        </Table.th>,
                        <Table.th key="date" className="py-2">
                          <div className="flex items-center space-x-2">
                            <p>Date</p>
                            <ButtonTooltip
                              type="text"
                              className="px-1"
                              icon={
                                dateSortDesc ? (
                                  <ArrowDown strokeWidth={1.5} size={14} />
                                ) : (
                                  <ArrowUp strokeWidth={1.5} size={14} />
                                )
                              }
                              onClick={() => setDateSortDesc(!dateSortDesc)}
                              tooltip={{
                                content: {
                                  side: 'bottom',
                                  text: dateSortDesc ? 'Sort latest first' : 'Sort earliest first',
                                },
                              }}
                            />
                          </div>
                        </Table.th>,
                        <Table.th key="actions" className="py-2"></Table.th>,
                      ]}
                      body={
                        sortedLogs?.map((log) => {
                          const project = projects?.find((p) => p.ref === log.project_ref)
                          const organization = organizations?.find(
                            (org) => org.slug === log.organization_slug
                          )
                          const isoTimestamp = dayjs(
                            log.timestamp / TIMESTAMP_MICROS_PER_MS
                          ).toISOString()

                          return (
                            <Table.tr
                              key={log.request_id}
                              onClick={() => setSelectedLog(log)}
                              className="cursor-pointer hover:bg-alternative! transition duration-100"
                            >
                              <Table.td className="max-w-[250px]">
                                <div className="flex items-center space-x-2">
                                  <p className="bg-surface-200 rounded-sm px-1 flex items-center justify-center text-xs font-mono border">
                                    {log.action.status}
                                  </p>
                                  <p className="text-foreground-light text-xs font-mono">
                                    {log.action.method}
                                  </p>
                                  <p className="truncate" title={log.action.name}>
                                    {log.action.name}
                                  </p>
                                </div>
                              </Table.td>
                              <Table.td>
                                {project || organization ? (
                                  <>
                                    <p
                                      className="text-foreground-light max-w-[230px] truncate"
                                      title={project?.name ?? organization?.name}
                                    >
                                      {project?.name
                                        ? 'Project: '
                                        : organization?.name
                                          ? 'Organization: '
                                          : null}
                                      {project?.name ?? organization?.name}
                                    </p>
                                    <p
                                      className="text-foreground-light text-xs mt-0.5 truncate"
                                      title={log.project_ref ?? log.organization_slug ?? ''}
                                    >
                                      {log.project_ref ? 'Ref: ' : 'Slug: '}
                                      {log.project_ref ?? log.organization_slug}
                                    </p>
                                  </>
                                ) : (
                                  <p className="text-foreground-light text-sm">
                                    {log.project_ref ?? log.organization_slug ?? '-'}
                                  </p>
                                )}
                              </Table.td>
                              <Table.td>
                                <TimestampInfo className="text-sm" utcTimestamp={isoTimestamp} />
                              </Table.td>
                              <Table.td align="right">
                                <Button type="default">View details</Button>
                              </Table.td>
                            </Table.tr>
                          )
                        }) ?? []
                      }
                    />
                  </div>
                )}
              </>
            )}
          </div>
        </ScaffoldSection>
      </ScaffoldContainer>

      <LogDetailsPanel selectedLog={selectedLog} onClose={() => setSelectedLog(undefined)} />
    </>
  )
}
