import { loggerService } from '@logger'
import AnthropicProviderListPopover from '@renderer/components/AnthropicProviderListPopover'
import { ErrorBoundary } from '@renderer/components/ErrorBoundary'
import Scrollbar from '@renderer/components/Scrollbar'
import { HelpTooltip } from '@renderer/components/TooltipIcons'
import { TopView } from '@renderer/components/TopView'
import { permissionModeCards } from '@renderer/config/agent'
import { isWin } from '@renderer/config/constant'
import { useAgents } from '@renderer/hooks/agents/useAgents'
import { useUpdateAgent } from '@renderer/hooks/agents/useUpdateAgent'
import SelectAgentBaseModelButton from '@renderer/pages/agents/components/SelectAgentBaseModelButton'
import type {
  AddAgentForm,
  AgentEntity,
  ApiModel,
  BaseAgentForm,
  PermissionMode,
  Tool,
  UpdateAgentForm
} from '@renderer/types'
import { AgentConfigurationSchema, isAgentType } from '@renderer/types'
import { parseKeyValueString, serializeKeyValueString } from '@renderer/utils/env'
import { getAnthropicSupportedProviders } from '@renderer/utils/provider'
import type { GitBashPathInfo } from '@shared/config/constant'
import { Button, Input, Modal, Select, Switch, Tooltip } from 'antd'
import { Info } from 'lucide-react'
import type { ChangeEvent, FormEvent } from 'react'
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import styled from 'styled-components'

const { TextArea } = Input

const logger = loggerService.withContext('AddAgentPopup')

type AgentWithTools = AgentEntity & { tools?: Tool[] }

const buildAgentForm = (existing?: AgentWithTools): BaseAgentForm => ({
  type: existing?.type ?? 'claude-code',
  name: existing?.name ?? 'Agent',
  description: existing?.description,
  instructions: existing?.instructions,
  model: existing?.model ?? '',
  accessible_paths: existing?.accessible_paths ? [...existing.accessible_paths] : [],
  allowed_tools: existing?.allowed_tools ? [...existing.allowed_tools] : [],
  mcps: existing?.mcps ? [...existing.mcps] : [],
  configuration: AgentConfigurationSchema.parse(existing?.configuration ?? {})
})

interface ShowParams {
  agent?: AgentWithTools
  afterSubmit?: (a: AgentEntity) => void
}

interface Props extends ShowParams {
  resolve: (data: any) => void
}

const PopupContainer: React.FC<Props> = ({ agent, afterSubmit, resolve }) => {
  const { t } = useTranslation()
  const [open, setOpen] = useState(true)
  const loadingRef = useRef(false)
  const { addAgent } = useAgents()
  const { updateAgent } = useUpdateAgent()
  const isEditing = (agent?: AgentWithTools) => agent !== undefined

  const [form, setForm] = useState<BaseAgentForm>(() => buildAgentForm(agent))
  const [gitBashPathInfo, setGitBashPathInfo] = useState<GitBashPathInfo>({ path: null, source: null })

  useEffect(() => {
    if (open) {
      setForm(buildAgentForm(agent))
    }
  }, [agent, open])

  const checkGitBash = useCallback(async () => {
    if (!isWin) return
    try {
      const pathInfo = await window.api.system.getGitBashPathInfo()
      setGitBashPathInfo(pathInfo)
    } catch (error) {
      logger.error('Failed to check Git Bash:', error as Error)
    }
  }, [])

  useEffect(() => {
    void checkGitBash()
  }, [checkGitBash])

  const selectedPermissionMode = form.configuration?.permission_mode ?? 'default'

  const handlePickGitBash = useCallback(async () => {
    try {
      const selected = await window.api.file.select({
        title: t('agent.gitBash.pick.title', 'Select Git Bash executable'),
        filters: [{ name: 'Executable', extensions: ['exe'] }],
        properties: ['openFile']
      })

      if (!selected || selected.length === 0) {
        return
      }

      const pickedPath = selected[0].path
      const ok = await window.api.system.setGitBashPath(pickedPath)
      if (!ok) {
        window.toast.error(
          t('agent.gitBash.pick.invalidPath', 'Selected file is not a valid Git Bash executable (bash.exe).')
        )
        return
      }

      await checkGitBash()
    } catch (error) {
      logger.error('Failed to pick Git Bash path', error as Error)
      window.toast.error(t('agent.gitBash.pick.failed', 'Failed to set Git Bash path'))
    }
  }, [checkGitBash, t])

  const handleResetGitBash = useCallback(async () => {
    try {
      // Clear manual setting and re-run auto-discovery
      await window.api.system.setGitBashPath(null)
      await checkGitBash()
    } catch (error) {
      logger.error('Failed to reset Git Bash path', error as Error)
    }
  }, [checkGitBash])

  const soulEnabled = form.configuration?.soul_enabled === true

  const onSoulModeChange = useCallback((checked: boolean) => {
    setForm((prev) => {
      const prevConfig = AgentConfigurationSchema.parse(prev.configuration ?? {})
      return {
        ...prev,
        configuration: {
          ...prevConfig,
          soul_enabled: checked,
          permission_mode: checked ? 'bypassPermissions' : prevConfig.permission_mode
        }
      }
    })
  }, [])

  const onPermissionModeChange = useCallback((value: PermissionMode) => {
    setForm((prev) => {
      const parsedConfiguration = AgentConfigurationSchema.parse(prev.configuration ?? {})
      if (parsedConfiguration.permission_mode === value) {
        if (!prev.configuration) {
          return {
            ...prev,
            configuration: parsedConfiguration
          }
        }
        return prev
      }

      const nextConfig = {
        ...parsedConfiguration,
        permission_mode: value
      }

      // Disable soul mode when switching away from bypassPermissions
      if (value !== 'bypassPermissions' && parsedConfiguration.soul_enabled === true) {
        nextConfig.soul_enabled = false
      }

      return {
        ...prev,
        configuration: nextConfig
      }
    })
  }, [])

  const onNameChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {
    setForm((prev) => ({
      ...prev,
      name: e.target.value
    }))
  }, [])

  // const onDescChange = useCallback((e: ChangeEvent<HTMLTextAreaElement>) => {
  //   setForm((prev) => ({
  //     ...prev,
  //     description: e.target.value
  //   }))
  // }, [])

  const onInstChange = useCallback((e: ChangeEvent<HTMLTextAreaElement>) => {
    setForm((prev) => ({
      ...prev,
      instructions: e.target.value
    }))
  }, [])

  const [envVarsText, setEnvVarsText] = useState(() => serializeKeyValueString(form.configuration?.env_vars ?? {}))

  useEffect(() => {
    if (open) {
      setEnvVarsText(serializeKeyValueString(buildAgentForm(agent).configuration?.env_vars ?? {}))
    }
  }, [agent, open])

  const onEnvVarsChange = useCallback((e: ChangeEvent<HTMLTextAreaElement>) => {
    const text = e.target.value
    setEnvVarsText(text)
    const parsed = parseKeyValueString(text)
    setForm((prev) => ({
      ...prev,
      configuration: {
        ...AgentConfigurationSchema.parse(prev.configuration ?? {}),
        env_vars: parsed
      }
    }))
  }, [])

  const addAccessiblePath = useCallback(async () => {
    try {
      const selected = await window.api.file.selectFolder()
      if (!selected) {
        return
      }
      setForm((prev) => {
        if (prev.accessible_paths.includes(selected)) {
          window.toast.warning(t('agent.session.accessible_paths.duplicate'))
          return prev
        }
        return {
          ...prev,
          accessible_paths: [...prev.accessible_paths, selected]
        }
      })
    } catch (error) {
      logger.error('Failed to select accessible path:', error as Error)
      window.toast.error(t('agent.session.accessible_paths.select_failed'))
    }
  }, [t])

  const removeAccessiblePath = useCallback((path: string) => {
    setForm((prev) => ({
      ...prev,
      accessible_paths: prev.accessible_paths.filter((item) => item !== path)
    }))
  }, [])

  // Create a temporary agentBase object for SelectAgentBaseModelButton
  const tempAgentBase: AgentEntity = useMemo(
    () => ({
      id: agent?.id ?? 'temp-creating',
      type: form.type,
      name: form.name,
      model: form.model,
      accessible_paths: form.accessible_paths.length > 0 ? form.accessible_paths : ['/'],
      allowed_tools: form.allowed_tools ?? [],
      description: form.description,
      instructions: form.instructions,
      configuration: form.configuration,
      created_at: agent?.created_at ?? new Date().toISOString(),
      updated_at: agent?.updated_at ?? new Date().toISOString()
    }),
    [form, agent?.id, agent?.created_at, agent?.updated_at]
  )

  const handleModelSelect = useCallback(async (model: ApiModel) => {
    setForm((prev) => ({ ...prev, model: model.id }))
  }, [])

  const onCancel = () => {
    setOpen(false)
  }

  const onClose = () => {
    resolve({})
  }

  const onSubmit = useCallback(
    async (e: FormEvent<HTMLFormElement>) => {
      e.preventDefault()
      if (loadingRef.current) {
        return
      }

      loadingRef.current = true

      // Additional validation check besides native HTML validation to ensure security
      if (!isAgentType(form.type)) {
        window.toast.error(t('agent.add.error.invalid_agent'))
        loadingRef.current = false
        return
      }
      if (!form.model) {
        window.toast.error(t('error.model.not_exists'))
        loadingRef.current = false
        return
      }

      if (isWin && !gitBashPathInfo.path) {
        window.toast.error(t('agent.gitBash.error.required', 'Git Bash path is required on Windows'))
        loadingRef.current = false
        return
      }

      if (isEditing(agent)) {
        if (!agent) {
          loadingRef.current = false
          throw new Error('Agent is required for editing mode')
        }

        const updatePayload = {
          id: agent.id,
          name: form.name,
          description: form.description,
          instructions: form.instructions,
          model: form.model,
          accessible_paths: [...form.accessible_paths],
          allowed_tools: [...form.allowed_tools],
          configuration: form.configuration ? { ...form.configuration } : undefined
        } satisfies UpdateAgentForm

        const result = await updateAgent(updatePayload)
        if (result) {
          logger.debug('Updated agent', result)
          afterSubmit?.(result)
        } else {
          logger.error('Update failed.')
        }
      } else {
        const newAgent = {
          type: form.type,
          name: form.name,
          description: form.description,
          instructions: form.instructions,
          model: form.model,
          accessible_paths: [...form.accessible_paths],
          allowed_tools: [...form.allowed_tools],
          configuration: form.configuration ? { ...form.configuration } : undefined
        } satisfies AddAgentForm
        const result = await addAgent(newAgent)

        if (!result.success) {
          loadingRef.current = false
          throw result.error
        }
        afterSubmit?.(result.data)
      }
      loadingRef.current = false
      setOpen(false)
    },
    [
      form.type,
      form.model,
      form.accessible_paths,
      form.name,
      form.description,
      form.instructions,
      form.allowed_tools,
      form.configuration,
      agent,
      t,
      updateAgent,
      afterSubmit,
      addAgent,
      gitBashPathInfo.path
    ]
  )

  AgentModalPopup.hide = onCancel

  return (
    <ErrorBoundary>
      <Modal
        title={isEditing(agent) ? t('agent.edit.title') : t('agent.add.title')}
        open={open}
        onCancel={onCancel}
        afterClose={onClose}
        transitionName="animation-move-down"
        centered
        width={500}
        footer={null}>
        <StyledForm onSubmit={onSubmit}>
          <FormContent>
            <FormRow>
              <FormItem style={{ flex: 1 }}>
                <Label>
                  {t('common.name')} <RequiredMark>*</RequiredMark>
                </Label>
                <Input value={form.name} onChange={onNameChange} required />
              </FormItem>
            </FormRow>

            <FormItem>
              <div className="flex items-center gap-2">
                <Label>
                  {t('common.model')} <RequiredMark>*</RequiredMark>
                </Label>
                <AnthropicProviderListPopover
                  useWindowNavigate
                  filterProviders={getAnthropicSupportedProviders}
                  onProviderClick={() => {
                    setOpen(false)
                    resolve(undefined)
                  }}
                />
              </div>
              <SelectAgentBaseModelButton
                agentBase={tempAgentBase}
                onSelect={handleModelSelect}
                fontSize={14}
                avatarSize={24}
                iconSize={16}
                buttonStyle={{
                  padding: '3px 8px',
                  width: '100%',
                  border: '1px solid var(--color-border)',
                  borderRadius: 6,
                  height: 'auto'
                }}
                containerClassName="flex items-center justify-between w-full"
              />
            </FormItem>

            {isWin && (
              <FormItem>
                <div className="flex items-center gap-2">
                  <Label>
                    Git Bash <RequiredMark>*</RequiredMark>
                  </Label>
                  <HelpTooltip
                    title={t(
                      'agent.gitBash.tooltip',
                      'Git Bash is required to run agents on Windows. Install from git-scm.com if not available.'
                    )}
                  />
                </div>
                <GitBashInputWrapper>
                  <Input
                    value={gitBashPathInfo.path ?? ''}
                    readOnly
                    placeholder={t('agent.gitBash.placeholder', 'Select bash.exe path')}
                  />
                  <Button size="small" onClick={handlePickGitBash}>
                    {t('common.select', 'Select')}
                  </Button>
                  {gitBashPathInfo.source === 'manual' && (
                    <Button size="small" onClick={handleResetGitBash}>
                      {t('common.reset', 'Reset')}
                    </Button>
                  )}
                </GitBashInputWrapper>
                {gitBashPathInfo.path && gitBashPathInfo.source === 'auto' && (
                  <SourceHint>{t('agent.gitBash.autoDiscoveredHint', 'Auto-discovered')}</SourceHint>
                )}
              </FormItem>
            )}

            <FormItem>
              <div className="flex items-center justify-between">
                <div className="flex items-center gap-2">
                  <Label>{t('agent.settings.soulMode.title')}</Label>
                  <Tooltip title={t('agent.settings.soulMode.description')} placement="right">
                    <Info size={16} className="text-foreground-400" />
                  </Tooltip>
                </div>
                <Switch checked={soulEnabled} size="small" onChange={onSoulModeChange} />
              </div>
            </FormItem>

            {!soulEnabled && (
              <FormItem>
                <Label>
                  {t('agent.settings.tooling.permissionMode.title', 'Permission mode')} <RequiredMark>*</RequiredMark>
                </Label>
                <Select
                  value={selectedPermissionMode}
                  onChange={onPermissionModeChange}
                  style={{ width: '100%' }}
                  placeholder={t('agent.settings.tooling.permissionMode.placeholder', 'Select permission mode')}
                  optionLabelProp="label">
                  {permissionModeCards.map((item) => (
                    <Select.Option key={item.mode} value={item.mode} label={t(item.titleKey, item.titleFallback)}>
                      <PermissionOptionWrapper>
                        <div className="title">{t(item.titleKey, item.titleFallback)}</div>
                        <div className="description">{t(item.descriptionKey, item.descriptionFallback)}</div>
                      </PermissionOptionWrapper>
                    </Select.Option>
                  ))}
                </Select>
                <HelpText>
                  {t('agent.settings.tooling.permissionMode.helper', 'Choose how the agent handles tool approvals.')}
                </HelpText>
              </FormItem>
            )}

            <FormItem>
              <LabelWithButton>
                <Label>{t('agent.session.accessible_paths.label')}</Label>
                <Button size="small" onClick={addAccessiblePath}>
                  {t('agent.session.accessible_paths.add')}
                </Button>
              </LabelWithButton>
              {form.accessible_paths.length > 0 ? (
                <PathList>
                  {form.accessible_paths.map((path) => (
                    <PathItem key={path}>
                      <PathText title={path}>{path}</PathText>
                      <Button size="small" danger onClick={() => removeAccessiblePath(path)}>
                        {t('common.delete')}
                      </Button>
                    </PathItem>
                  ))}
                </PathList>
              ) : (
                <HelpText>
                  {t(
                    'agent.session.accessible_paths.default_hint',
                    'A default workspace will be created automatically if not specified.'
                  )}
                </HelpText>
              )}
            </FormItem>

            <FormItem>
              <Label>{t('common.prompt')}</Label>
              <TextArea rows={3} value={form.instructions ?? ''} onChange={onInstChange} />
            </FormItem>

            <FormItem>
              <Label>{t('agent.settings.advance.envVars.label')}</Label>
              <TextArea
                rows={3}
                value={envVarsText}
                onChange={onEnvVarsChange}
                placeholder={'API_KEY=xxx\nDEBUG=true'}
              />
              <HelpText>{t('agent.settings.advance.envVars.helper')}</HelpText>
            </FormItem>

            {/* <FormItem>
              <Label>{t('common.description')}</Label>
              <TextArea rows={1} value={form.description ?? ''} onChange={onDescChange} />
            </FormItem> */}
          </FormContent>

          <FormFooter>
            <Button onClick={onCancel}>{t('common.close')}</Button>
            <Button
              type="primary"
              htmlType="submit"
              loading={loadingRef.current}
              disabled={isWin && !gitBashPathInfo.path}>
              {isEditing(agent) ? t('common.confirm') : t('common.add')}
            </Button>
          </FormFooter>
        </StyledForm>
      </Modal>
    </ErrorBoundary>
  )
}

const TopViewKey = 'AgentModalPopup'

export default class AgentModalPopup {
  static topviewId = 0
  static hide() {
    TopView.hide(TopViewKey)
  }
  static show(props: ShowParams) {
    return new Promise<any>((resolve) => {
      TopView.show(
        <PopupContainer
          {...props}
          resolve={(v) => {
            resolve(v)
            TopView.hide(TopViewKey)
          }}
        />,
        TopViewKey
      )
    })
  }
}

// Keep the old export for backward compatibility during migration
export const AgentModal = AgentModalPopup

const StyledForm = styled.form`
  display: flex;
  flex-direction: column;
  gap: 16px;
`

const FormContent = styled(Scrollbar)`
  display: flex;
  flex-direction: column;
  gap: 16px;
  max-height: 60vh;
  padding-right: 8px;
`

const FormRow = styled.div`
  display: flex;
  gap: 12px;
`

const FormItem = styled.div`
  display: flex;
  flex-direction: column;
  gap: 8px;
`

const GitBashInputWrapper = styled.div`
  display: flex;
  gap: 8px;
  align-items: center;

  input {
    flex: 1;
  }
`

const SourceHint = styled.span`
  font-size: 12px;
  color: var(--color-text-3);
`

const Label = styled.label`
  font-size: 14px;
  color: var(--color-text-1);
  font-weight: 500;
`

const RequiredMark = styled.span`
  color: #ff4d4f;
  margin-left: 4px;
`

const HelpText = styled.div`
  font-size: 12px;
  color: var(--color-text-3);
`

const LabelWithButton = styled.div`
  display: flex;
  justify-content: space-between;
  align-items: center;
`

const PathList = styled.div`
  display: flex;
  flex-direction: column;
  gap: 8px;
`

const PathItem = styled.div`
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 8px 12px;
  border: 1px solid var(--color-border);
  border-radius: 6px;
  background-color: var(--color-bg-1);
`

const PathText = styled.span`
  flex: 1;
  font-size: 13px;
  color: var(--color-text-2);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
`

const FormFooter = styled.div`
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  padding: 10px;
`

const PermissionOptionWrapper = styled.div`
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 8px 0;

  .title {
    font-size: 14px;
    font-weight: 600;
    color: var(--color-text-1);
    margin-bottom: 2px;
  }

  .description {
    font-size: 12px;
    color: var(--color-text-2);
    line-height: 1.4;
  }

  .behavior {
    font-size: 12px;
    color: var(--color-text-3);
    line-height: 1.4;
  }

  .caution {
    display: flex;
    align-items: flex-start;
    gap: 6px;
    font-size: 12px;
    color: #ff4d4f;
    margin-top: 4px;
    padding: 6px 8px;
    background-color: rgba(255, 77, 79, 0.1);
    border-radius: 4px;

    svg {
      flex-shrink: 0;
      margin-top: 2px;
    }
  }
`
