import { zodResolver } from '@hookform/resolvers/zod'
import { PermissionAction } from '@supabase/shared-types/out/constants'
import { useParams } from 'common'
import { useEffect } from 'react'
import { useForm } from 'react-hook-form'
import { toast } from 'sonner'
import { Button, Card, CardContent, CardFooter, Form, FormControl, FormField, Switch } from 'ui'
import { Admonition, GenericSkeletonLoader } from 'ui-patterns'
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
import {
  PageSection,
  PageSectionContent,
  PageSectionMeta,
  PageSectionSummary,
  PageSectionTitle,
} from 'ui-patterns/PageSection'
import * as z from 'zod'

import { AlertError } from '@/components/ui/AlertError'
import { InlineLink } from '@/components/ui/InlineLink'
import { useAuthConfigQuery } from '@/data/auth/auth-config-query'
import { useAuthConfigUpdateMutation } from '@/data/auth/auth-config-update-mutation'
import { useTablesQuery } from '@/data/tables/tables-query'
import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions'
import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'

const schema = z.object({
  AUDIT_LOG_DISABLE_POSTGRES: z.boolean(),
})

const AUDIT_LOG_ENTRIES_TABLE = 'audit_log_entries'

export const AuditLogsForm = () => {
  const { ref: projectRef } = useParams()
  const { data: project } = useSelectedProjectQuery()

  const { can: canUpdateConfig } = useAsyncCheckPermissions(
    PermissionAction.UPDATE,
    'custom_config_gotrue'
  )

  const { data: tables = [] } = useTablesQuery({
    projectRef: project?.ref,
    connectionString: project?.connectionString,
    includeColumns: false,
    schema: 'auth',
  })
  const auditLogTable = tables.find((x) => x.name === AUDIT_LOG_ENTRIES_TABLE)

  const {
    data: authConfig,
    error: authConfigError,
    isError,
    isPending: isLoading,
  } = useAuthConfigQuery({ projectRef })

  const { mutate: updateAuthConfig, isPending: isUpdatingConfig } = useAuthConfigUpdateMutation({
    onError: (error) => {
      toast.error(`Failed to update audit logs: ${error?.message}`)
    },
    onSuccess: () => {
      toast.success('Successfully updated audit logs settings')
    },
  })

  const form = useForm({
    resolver: zodResolver(schema as any),
    defaultValues: { AUDIT_LOG_DISABLE_POSTGRES: false },
  })
  const { isDirty } = form.formState
  const { AUDIT_LOG_DISABLE_POSTGRES: formValueDisablePostgres } = form.watch()
  const currentlyDisabled = authConfig?.AUDIT_LOG_DISABLE_POSTGRES ?? false
  const isDisabling = !currentlyDisabled && formValueDisablePostgres

  const onSubmitAuditLogs = (values: any) => {
    if (!projectRef) return console.error('Project ref is required')
    updateAuthConfig({ projectRef: projectRef, config: values })
  }

  useEffect(() => {
    if (authConfig) {
      form.reset({ AUDIT_LOG_DISABLE_POSTGRES: authConfig?.AUDIT_LOG_DISABLE_POSTGRES ?? false })
    }
  }, [authConfig])

  if (isError) {
    return (
      <PageSection>
        <PageSectionContent>
          <AlertError
            error={authConfigError}
            subject="Failed to retrieve auth configuration for hooks"
          />
        </PageSectionContent>
      </PageSection>
    )
  }

  if (isLoading) {
    return (
      <PageSection>
        <PageSectionContent>
          <GenericSkeletonLoader />
        </PageSectionContent>
      </PageSection>
    )
  }

  return (
    <PageSection>
      <PageSectionMeta>
        <PageSectionSummary>
          <PageSectionTitle>Settings</PageSectionTitle>
        </PageSectionSummary>
      </PageSectionMeta>
      <PageSectionContent>
        <Form {...form}>
          <form onSubmit={form.handleSubmit(onSubmitAuditLogs)} className="space-y-4">
            <Card>
              <CardContent>
                <FormField
                  control={form.control}
                  name="AUDIT_LOG_DISABLE_POSTGRES"
                  render={({ field }) => (
                    <FormItemLayout
                      layout="flex-row-reverse"
                      label="Write audit logs to the database"
                      description={
                        <p className="text-sm prose text-foreground-lighter max-w-full">
                          When enabled, audit logs are written to the{' '}
                          <InlineLink
                            target="_blank"
                            rel="noopener noreferrer"
                            href={`/project/${projectRef}/editor/${auditLogTable?.id}`}
                          >
                            <code className="text-code-inline">{AUDIT_LOG_ENTRIES_TABLE}</code>
                          </InlineLink>{' '}
                          table.
                          <br />
                          You can disable this to reduce disk usage while still accessing logs
                          through the{' '}
                          <InlineLink
                            href={`/project/${projectRef}/logs/explorer?q=select%0A++cast(timestamp+as+datetime)+as+timestamp%2C%0A++event_message%2C+metadata+%0Afrom+auth_audit_logs+%0Alimit+10%0A`}
                          >
                            Auth logs
                          </InlineLink>
                          .
                        </p>
                      }
                    >
                      <FormControl>
                        <Switch
                          checked={!field.value}
                          onCheckedChange={(value) => field.onChange(!value)}
                          disabled={!canUpdateConfig}
                        />
                      </FormControl>
                    </FormItemLayout>
                  )}
                />
                {isDisabling && (
                  <Admonition
                    type="warning"
                    className="mt-4"
                    title="Disabling PostgreSQL storage will not automatically migrate or transfer existing audit log data"
                    description={
                      <p>
                        Future audit logs will only appear in the project’s{' '}
                        <InlineLink
                          href={`/project/${projectRef}/logs/explorer?q=select%0A++cast(timestamp+as+datetime)+as+timestamp%2C%0A++event_message%2C+metadata+%0Afrom+auth_audit_logs+%0Alimit+10%0A`}
                        >
                          auth logs
                        </InlineLink>
                        . You are responsible for backing up, copying, or migrating existing data
                        from the{' '}
                        <code className="text-code-inline break-keep!">
                          {AUDIT_LOG_ENTRIES_TABLE}
                        </code>{' '}
                        table if needed.
                      </p>
                    }
                  />
                )}
              </CardContent>

              <CardFooter className="justify-end space-x-2">
                {isDirty && (
                  <Button type="default" onClick={() => form.reset()}>
                    Cancel
                  </Button>
                )}
                <Button
                  type="primary"
                  htmlType="submit"
                  disabled={!canUpdateConfig || isUpdatingConfig || !isDirty}
                  loading={isUpdatingConfig}
                >
                  Save changes
                </Button>
              </CardFooter>
            </Card>
          </form>
        </Form>
      </PageSectionContent>
    </PageSection>
  )
}
