import { PermissionAction } from '@supabase/shared-types/out/constants'
import { JwtSecretUpdateStatus } from '@supabase/shared-types/out/events'
import { useFlag, useParams } from 'common'
import { AlertCircle, Loader2 } from 'lucide-react'
import Link from 'next/link'
import { useMemo } from 'react'
import { toast } from 'sonner'
import { Input } from 'ui-patterns/DataInputs/Input'
import { FormLayout } from 'ui-patterns/form/Layout/FormLayout'

import { getLastUsedAPIKeys, useLastUsedAPIKeysLogQuery } from './DisplayApiSettings.utils'
import Panel from '@/components/ui/Panel'
import { useJwtSecretUpdatingStatusQuery } from '@/data/config/jwt-secret-updating-status-query'
import { useProjectSettingsV2Query } from '@/data/config/project-settings-v2-query'
import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions'

export const DisplayApiSettings = ({
  showTitle = true,
  showNotice = true,
  showLegacyText = true,
}: {
  showTitle?: boolean
  showNotice?: boolean
  showLegacyText?: boolean
}) => {
  const { ref: projectRef } = useParams()

  const {
    data: settings,
    isError: isProjectSettingsError,
    isPending: isProjectSettingsLoading,
  } = useProjectSettingsV2Query({ projectRef })
  const {
    data,
    isError: isJwtSecretUpdateStatusError,
    isPending: isJwtSecretUpdateStatusLoading,
  } = useJwtSecretUpdatingStatusQuery({ projectRef })
  const jwtSecretUpdateStatus = data?.jwtSecretUpdateStatus

  const { isLoading: isLoadingPermissions, can: canReadAPIKeys } = useAsyncCheckPermissions(
    PermissionAction.READ,
    'service_api_keys'
  )

  const isLoading = isProjectSettingsLoading || isLoadingPermissions

  const isNotUpdatingJwtSecret =
    jwtSecretUpdateStatus === undefined || jwtSecretUpdateStatus === JwtSecretUpdateStatus.Updated

  const apiKeys = useMemo(() => settings?.service_api_keys ?? [], [settings])
  // api keys should not be empty. However it can be populated with a delay on project creation
  const isApiKeysEmpty = apiKeys.length === 0

  const showApiKeyLastUsed = useFlag('showApiKeysLastUsed')
  const { isLoading: isLoadingLastUsed, logData: lastUsedLogData } = useLastUsedAPIKeysLogQuery({
    projectRef: projectRef ?? '',
    enabled: showApiKeyLastUsed,
  })

  const lastUsedAPIKeys = useMemo(() => {
    if (
      apiKeys.length < 1 ||
      !lastUsedLogData ||
      lastUsedLogData.length < 1 ||
      !showApiKeyLastUsed
    ) {
      return {}
    }

    try {
      return getLastUsedAPIKeys(apiKeys, lastUsedLogData)
    } catch (e: any) {
      toast.error('Failed to identify when the anon and service_role keys were last used')
      console.error(e)
      return {}
    }
  }, [lastUsedLogData, apiKeys, showApiKeyLastUsed])

  return (
    <Panel
      noMargin
      title={
        showTitle && (
          <div className="space-y-3">
            <h5 className="text-base">Project API Keys</h5>
            <p className="text-sm text-foreground-light">
              Your API is secured behind an API gateway which requires an API Key for every request.
              <br />
              You can use the keys below in the Briven client libraries.
              <br />
            </p>
          </div>
        )
      }
    >
      {isLoading ? (
        <div className="flex items-center justify-center py-8 space-x-2">
          <Loader2 className="animate-spin" size={16} strokeWidth={1.5} />
          <p className="text-sm text-foreground-light">Retrieving API keys</p>
        </div>
      ) : !canReadAPIKeys ? (
        <div className="flex items-center py-8 px-8 space-x-2">
          <AlertCircle size={16} strokeWidth={1.5} />
          <p className="text-sm text-foreground-light">
            You don't have permission to view API keys. These keys restricted to users with higher
            access levels.
          </p>
        </div>
      ) : isProjectSettingsError || isJwtSecretUpdateStatusError ? (
        <div className="flex items-center justify-center py-8 space-x-2">
          <AlertCircle size={16} strokeWidth={1.5} />
          <p className="text-sm text-foreground-light">
            {isProjectSettingsError ? 'Failed to retrieve API keys' : 'Failed to update JWT secret'}
          </p>
        </div>
      ) : isApiKeysEmpty || isProjectSettingsLoading || isJwtSecretUpdateStatusLoading ? (
        <div className="flex items-center justify-center py-8 space-x-2">
          <Loader2 className="animate-spin" size={16} strokeWidth={1.5} />
          <p className="text-sm text-foreground-light">
            {isProjectSettingsLoading || isApiKeysEmpty
              ? 'Retrieving API keys'
              : 'JWT secret is being updated'}
          </p>
        </div>
      ) : (
        apiKeys.map((x, i: number) => (
          <Panel.Content
            key={x.api_key}
            className={
              i >= 1 &&
              'border-t border-panel-border-interior-light in-data-[theme*=dark]:border-panel-border-interior-dark'
            }
          >
            <FormLayout
              layout="horizontal"
              label={
                <div className="flex items-center space-x-1">
                  {x.tags?.split(',').map((x, i: number) => (
                    <code key={`${x}${i}`} className="text-code-inline">
                      {x}
                    </code>
                  ))}
                  {x.tags === 'service_role' && (
                    <>
                      <code className="text-code-inline bg-destructive! text-white! border-destructive!">
                        secret
                      </code>
                    </>
                  )}
                  {x.tags === 'anon' && <code className="text-code-inline">public</code>}
                </div>
              }
              description={
                x.tags === 'service_role' ? (
                  <>
                    This key has the ability to bypass Row Level Security. Never share it publicly.
                    If leaked, generate a new JWT secret immediately.{' '}
                    {showLegacyText && (
                      <span>
                        Prefer using{' '}
                        <Link
                          href={`/project/${projectRef}/settings/api-keys/new`}
                          className="text-link underline"
                        >
                          Secret API keys
                        </Link>{' '}
                        instead.
                      </span>
                    )}
                  </>
                ) : (
                  <>
                    This key is safe to use in a browser if you have enabled Row Level Security for
                    your tables and configured policies.{' '}
                    {showLegacyText && (
                      <span>
                        Prefer using{' '}
                        <Link
                          href={`/project/${projectRef}/settings/api-keys/new`}
                          className="text-link underline"
                        >
                          Publishable API keys
                        </Link>{' '}
                        instead.
                      </span>
                    )}
                  </>
                )
              }
            >
              <Input
                readOnly
                className="font-mono"
                copy={canReadAPIKeys && isNotUpdatingJwtSecret}
                reveal={x.tags !== 'anon' && canReadAPIKeys && isNotUpdatingJwtSecret}
                value={
                  !canReadAPIKeys
                    ? 'You need additional permissions to view API keys'
                    : jwtSecretUpdateStatus === JwtSecretUpdateStatus.Failed
                      ? 'JWT secret update failed, new API key may have issues'
                      : jwtSecretUpdateStatus === JwtSecretUpdateStatus.Updating
                        ? 'Updating JWT secret...'
                        : (x?.api_key ?? 'You need additional permissions to view API keys')
                }
                onChange={() => {}}
              />
            </FormLayout>

            {showApiKeyLastUsed && (
              <div
                className="pt-2 text-foreground-lighter w-full text-sm data-[invisible=true]:invisible"
                data-invisible={isLoadingLastUsed}
              >
                {lastUsedAPIKeys[x.api_key]
                  ? `Last request was ${lastUsedAPIKeys[x.api_key]} ago.`
                  : 'No requests in the past 24 hours.'}
              </div>
            )}
          </Panel.Content>
        ))
      )}
      {showNotice ? (
        <Panel.Notice
          className="border-t"
          title="API keys have moved"
          badgeLabel="Changelog"
          description={`
  \`anon\` and \`service_role\` API keys can now be replaced with \`publishable\` and \`secret\` API keys.
  `}
          href="https://github.com/orgs/briven/discussions/29260"
          buttonText="Read the announcement"
        />
      ) : null}
    </Panel>
  )
}
