'use client'

import { createElement, useCallback, useMemo, useRef, useState } from 'react'
import { ExternalLink } from 'lucide-react'
import { useParams } from 'next/navigation'
import { Button, Combobox } from '@/components/emcn/components'
import { consumeOAuthReturnContext, writeOAuthReturnContext } from '@/lib/credentials/client-state'
import {
  getCanonicalScopesForProvider,
  getProviderIdFromServiceId,
  getServiceConfigByProviderId,
  OAUTH_PROVIDERS,
  type OAuthProvider,
  type OAuthService,
  parseProvider,
} from '@/lib/oauth'
import { getMissingRequiredScopes } from '@/lib/oauth/utils'
import { OAuthModal } from '@/app/workspace/[workspaceId]/components/oauth-modal'
import { useWorkspaceCredential } from '@/hooks/queries/credentials'
import { useOAuthCredentials } from '@/hooks/queries/oauth/oauth-credentials'
import { useWorkflowMap } from '@/hooks/queries/workflows'
import { useCredentialRefreshTriggers } from '@/hooks/use-credential-refresh-triggers'
import { useWorkflowRegistry } from '@/stores/workflows/registry/store'

const getProviderIcon = (providerName: OAuthProvider) => {
  const { baseProvider } = parseProvider(providerName)
  const baseProviderConfig = OAUTH_PROVIDERS[baseProvider]

  if (!baseProviderConfig) {
    return <ExternalLink className='h-3 w-3' />
  }
  return createElement(baseProviderConfig.icon, { className: 'h-3 w-3' })
}

const getProviderName = (providerName: OAuthProvider) => {
  const serviceConfig = getServiceConfigByProviderId(providerName)
  if (serviceConfig) {
    return serviceConfig.name
  }

  const { baseProvider } = parseProvider(providerName)
  const baseProviderConfig = OAUTH_PROVIDERS[baseProvider]

  if (baseProviderConfig) {
    return baseProviderConfig.name
  }

  return providerName
    .split('-')
    .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
    .join(' ')
}

interface ToolCredentialSelectorProps {
  value: string
  onChange: (value: string) => void
  provider: OAuthProvider
  requiredScopes?: string[]
  label?: string
  serviceId: OAuthService
  disabled?: boolean
}

export function ToolCredentialSelector({
  value,
  onChange,
  provider,
  requiredScopes = [],
  label,
  serviceId,
  disabled = false,
}: ToolCredentialSelectorProps) {
  const params = useParams()
  const workspaceId = (params?.workspaceId as string) || ''
  const onChangeRef = useRef(onChange)
  onChangeRef.current = onChange
  const [showConnectModal, setShowConnectModal] = useState(false)
  const [showOAuthModal, setShowOAuthModal] = useState(false)
  const [editingInputValue, setEditingInputValue] = useState('')
  const [isEditing, setIsEditing] = useState(false)
  const activeWorkflowId = useWorkflowRegistry((s) => s.activeWorkflowId)
  const { data: workflowMap = {} } = useWorkflowMap(workspaceId)
  const effectiveWorkflowId =
    activeWorkflowId && workflowMap[activeWorkflowId] ? activeWorkflowId : undefined

  const selectedId = value || ''
  const effectiveLabel = label || `Select ${getProviderName(provider)} account`

  const effectiveProviderId = useMemo(() => getProviderIdFromServiceId(serviceId), [serviceId])

  const {
    data: credentials = [],
    isFetching: credentialsLoading,
    refetch: refetchCredentials,
  } = useOAuthCredentials(effectiveProviderId, {
    enabled: Boolean(effectiveProviderId),
    workspaceId,
    workflowId: effectiveWorkflowId,
  })

  const selectedCredential = useMemo(
    () => credentials.find((cred) => cred.id === selectedId),
    [credentials, selectedId]
  )

  const { data: inaccessibleCredential } = useWorkspaceCredential(
    selectedId || undefined,
    Boolean(selectedId) && !selectedCredential && !credentialsLoading && Boolean(workspaceId)
  )
  const inaccessibleCredentialName = inaccessibleCredential?.displayName ?? null

  const resolvedLabel = useMemo(() => {
    if (selectedCredential) return selectedCredential.name
    if (inaccessibleCredentialName) return inaccessibleCredentialName
    return ''
  }, [selectedCredential, inaccessibleCredentialName])

  const inputValue = isEditing ? editingInputValue : resolvedLabel

  useCredentialRefreshTriggers(refetchCredentials, effectiveProviderId, workspaceId)

  const handleOpenChange = useCallback(
    (isOpen: boolean) => {
      if (isOpen) {
        void refetchCredentials()
      }
    },
    [refetchCredentials]
  )

  const hasSelection = Boolean(selectedCredential)
  const missingRequiredScopes = hasSelection
    ? getMissingRequiredScopes(selectedCredential!, requiredScopes || [])
    : []

  const needsUpdate =
    hasSelection && missingRequiredScopes.length > 0 && !disabled && !credentialsLoading

  const handleSelect = useCallback(
    (credentialId: string) => {
      onChange(credentialId)
      setIsEditing(false)
    },
    [onChange]
  )

  const handleAddCredential = useCallback(() => {
    setShowConnectModal(true)
  }, [])

  const comboboxOptions = useMemo(() => {
    const options = credentials.map((cred) => ({
      label: cred.name,
      value: cred.id,
    }))

    options.push({
      label:
        credentials.length > 0
          ? `Connect another ${getProviderName(provider)} account`
          : `Connect ${getProviderName(provider)} account`,
      value: '__connect_account__',
    })

    return options
  }, [credentials, provider])

  const selectedCredentialProvider = selectedCredential?.provider ?? provider

  const overlayContent = useMemo(() => {
    if (!inputValue) return null

    return (
      <div className='flex w-full items-center truncate'>
        <div className='mr-2 flex-shrink-0 opacity-90'>
          {getProviderIcon(selectedCredentialProvider)}
        </div>
        <span className='truncate'>{inputValue}</span>
      </div>
    )
  }, [inputValue, selectedCredentialProvider])

  const handleComboboxChange = useCallback(
    (newValue: string) => {
      if (newValue === '__connect_account__') {
        handleAddCredential()
        return
      }

      const matchedCred = credentials.find((c) => c.id === newValue)
      if (matchedCred) {
        handleSelect(newValue)
        return
      }

      setIsEditing(true)
      setEditingInputValue(newValue)
    },
    [credentials, handleAddCredential, handleSelect]
  )

  return (
    <div>
      <Combobox
        options={comboboxOptions}
        value={inputValue}
        selectedValue={selectedId}
        onChange={handleComboboxChange}
        onOpenChange={handleOpenChange}
        placeholder={effectiveLabel}
        disabled={disabled}
        editable={true}
        filterOptions={true}
        isLoading={credentialsLoading}
        overlayContent={overlayContent}
        className={selectedId ? 'pl-7' : ''}
      />

      {needsUpdate && (
        <div className='mt-2 flex flex-col gap-1 rounded-sm border bg-[var(--surface-2)] px-2 py-1.5'>
          <div className='flex items-center font-medium text-caption'>
            <span className='mr-1.5 inline-block h-[6px] w-[6px] rounded-xs bg-amber-500' />
            Additional permissions required
          </div>
          <Button
            variant='active'
            onClick={() => {
              writeOAuthReturnContext({
                origin: 'workflow',
                workflowId: effectiveWorkflowId || '',
                displayName: selectedCredential?.name ?? getProviderName(provider),
                providerId: effectiveProviderId,
                preCount: credentials.length,
                workspaceId,
                requestedAt: Date.now(),
              })
              setShowOAuthModal(true)
            }}
            className='w-full px-2 py-1 font-medium text-caption'
          >
            Update access
          </Button>
        </div>
      )}

      {showConnectModal && (
        <OAuthModal
          mode='connect'
          isOpen={showConnectModal}
          onClose={() => setShowConnectModal(false)}
          provider={provider}
          serviceId={serviceId}
          workspaceId={workspaceId}
          workflowId={effectiveWorkflowId || ''}
          credentialCount={credentials.length}
        />
      )}

      {showOAuthModal && (
        <OAuthModal
          mode='reauthorize'
          isOpen={showOAuthModal}
          onClose={() => {
            consumeOAuthReturnContext()
            setShowOAuthModal(false)
          }}
          provider={provider}
          toolName={getProviderName(provider)}
          requiredScopes={getCanonicalScopesForProvider(effectiveProviderId)}
          newScopes={missingRequiredScopes}
          serviceId={serviceId}
        />
      )}
    </div>
  )
}
