/*
Copyright (C) 2023-2026 MAX-API-Next

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.

For commercial licensing, please contact https://github.com/MAX-API-Next/MAX-API/issues
*/
import { useEffect, useMemo } from 'react'
import { z } from 'zod'
import { useForm, type Resolver } from 'react-hook-form'
import { zodResolver } from '@hookform/resolvers/zod'
import { useQuery, useQueryClient } from '@tanstack/react-query'
import { Loader2 } from 'lucide-react'
import { useTranslation } from 'react-i18next'
import { toast } from 'sonner'
import { Button } from '@/components/ui/button'
import {
  Collapsible,
  CollapsibleContent,
  CollapsibleTrigger,
} from '@/components/ui/collapsible'
import {
  Dialog,
  DialogContent,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from '@/components/ui/dialog'
import {
  Form,
  FormControl,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from '@/components/ui/form'
import { Input } from '@/components/ui/input'
import { Textarea } from '@/components/ui/textarea'
import { getDeployment, updateDeployment } from '../../api'
import { deploymentsQueryKeys } from '../../lib'

const schema = z.object({
  image_url: z.string().optional(),
  traffic_port: z.coerce.number().int().min(1).max(65535).optional(),
  entrypoint: z.string().optional(),
  args: z.string().optional(),
  command: z.string().optional(),
  registry_username: z.string().optional(),
  registry_secret: z.string().optional(),
  env_json: z.string().optional(),
  secret_env_json: z.string().optional(),
})

type Values = z.input<typeof schema>

function normalizeJsonObject(input?: string) {
  if (!input || !input.trim()) return undefined
  const parsed = JSON.parse(input)
  if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
    throw new Error('JSON must be an object')
  }
  return Object.fromEntries(
    Object.entries(parsed as Record<string, unknown>).map(([k, v]) => [
      k,
      String(v),
    ])
  ) as Record<string, string>
}

export function UpdateConfigDialog({
  open,
  onOpenChange,
  deploymentId,
}: {
  open: boolean
  onOpenChange: (open: boolean) => void
  deploymentId: string | number | null
}) {
  const { t } = useTranslation()
  const queryClient = useQueryClient()

  const form = useForm<Values>({
    resolver: zodResolver(schema) as unknown as Resolver<Values>,
    defaultValues: {
      image_url: '',
      traffic_port: undefined,
      entrypoint: '',
      args: '',
      command: '',
      registry_username: '',
      registry_secret: '',
      env_json: '',
      secret_env_json: '',
    },
  })

  const { data: detailsRes, isLoading } = useQuery({
    queryKey: ['deployment-details-for-update', deploymentId],
    queryFn: () => (deploymentId ? getDeployment(deploymentId) : null),
    enabled: open && deploymentId !== null,
  })

  const details = detailsRes?.data

  useEffect(() => {
    if (!open || !details) return
    const containerConfig =
      details.container_config && typeof details.container_config === 'object'
        ? (details.container_config as Record<string, unknown>)
        : {}
    const imageUrl =
      typeof containerConfig.image_url === 'string'
        ? containerConfig.image_url
        : ''
    const trafficPort =
      typeof containerConfig.traffic_port === 'number'
        ? containerConfig.traffic_port
        : undefined
    const entrypointArr = Array.isArray(containerConfig.entrypoint)
      ? (containerConfig.entrypoint as unknown[])
          .map((x) => (typeof x === 'string' ? x : ''))
          .filter(Boolean)
      : []
    const envVars =
      containerConfig.env_variables &&
      typeof containerConfig.env_variables === 'object' &&
      !Array.isArray(containerConfig.env_variables)
        ? (containerConfig.env_variables as Record<string, unknown>)
        : {}

    form.reset({
      image_url: imageUrl,
      traffic_port: trafficPort,
      entrypoint: entrypointArr.join(' '),
      args: '',
      command: '',
      registry_username: '',
      registry_secret: '',
      env_json: Object.keys(envVars).length
        ? JSON.stringify(envVars, null, 2)
        : '',
      secret_env_json: '',
    })
  }, [open, details, form])

  const title = useMemo(
    () =>
      deploymentId
        ? `${t('Update configuration')} - ${deploymentId}`
        : t('Update configuration'),
    [deploymentId, t]
  )

  const onSubmit = async (values: Values) => {
    if (!deploymentId) return
    try {
      const env_variables = normalizeJsonObject(values.env_json)
      const secret_env_variables = normalizeJsonObject(values.secret_env_json)
      const entrypoint = values.entrypoint
        ? values.entrypoint
            .split(' ')
            .map((x) => x.trim())
            .filter(Boolean)
        : undefined
      const args = values.args
        ? values.args
            .split(' ')
            .map((x) => x.trim())
            .filter(Boolean)
        : undefined

      const res = await updateDeployment(deploymentId, {
        image_url: values.image_url?.trim() || undefined,
        traffic_port:
          typeof values.traffic_port === 'number'
            ? values.traffic_port
            : undefined,
        registry_username: values.registry_username?.trim() || undefined,
        registry_secret: values.registry_secret?.trim() || undefined,
        command: values.command?.trim() || undefined,
        ...(entrypoint?.length ? { entrypoint } : {}),
        ...(args?.length ? { args } : {}),
        ...(env_variables ? { env_variables } : {}),
        ...(secret_env_variables ? { secret_env_variables } : {}),
      })

      if (res.success) {
        toast.success(t('Updated successfully'))
        queryClient.invalidateQueries({
          queryKey: deploymentsQueryKeys.lists(),
        })
        queryClient.invalidateQueries({ queryKey: ['deployment-details'] })
        onOpenChange(false)
        return
      }
      toast.error(res.message || t('Update failed'))
    } catch (err: unknown) {
      const msg = err instanceof Error ? err.message : t('Update failed')
      toast.error(msg)
    }
  }

  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent className='max-h-[calc(100dvh-2rem)] overflow-hidden max-sm:w-screen max-sm:max-w-none max-sm:rounded-none max-sm:p-4 sm:max-w-3xl'>
        <DialogHeader>
          <DialogTitle>{title}</DialogTitle>
        </DialogHeader>

        {isLoading ? (
          <div className='flex items-center justify-center py-10'>
            <Loader2 className='text-muted-foreground h-6 w-6 animate-spin' />
          </div>
        ) : (
          <div className='max-h-[calc(100dvh-8.5rem)] overflow-y-auto py-2 pr-1 sm:max-h-[72vh]'>
            <Form {...form}>
              <form
                onSubmit={form.handleSubmit(onSubmit)}
                autoComplete='off'
                className='space-y-4'
              >
                <div className='grid gap-3 md:grid-cols-2 md:gap-4'>
                  <FormField
                    control={form.control}
                    name='image_url'
                    render={({ field }) => (
                      <FormItem>
                        <FormLabel>{t('Image')}</FormLabel>
                        <FormControl>
                          <Input
                            placeholder='ollama/ollama:latest'
                            {...field}
                          />
                        </FormControl>
                        <FormMessage />
                      </FormItem>
                    )}
                  />

                  <FormField
                    control={form.control}
                    name='traffic_port'
                    render={({ field }) => (
                      <FormItem>
                        <FormLabel>{t('Port')}</FormLabel>
                        <FormControl>
                          <Input
                            type='number'
                            min={1}
                            max={65535}
                            value={
                              typeof field.value === 'number' ||
                              typeof field.value === 'string'
                                ? field.value
                                : ''
                            }
                            onChange={(e) => {
                              const v = e.target.value
                              field.onChange(v === '' ? undefined : Number(v))
                            }}
                            onBlur={field.onBlur}
                            name={field.name}
                            ref={field.ref}
                          />
                        </FormControl>
                        <FormMessage />
                      </FormItem>
                    )}
                  />
                </div>

                <div className='grid gap-3 md:grid-cols-2 md:gap-4'>
                  <FormField
                    control={form.control}
                    name='entrypoint'
                    render={({ field }) => (
                      <FormItem>
                        <FormLabel>
                          {t('Entrypoint (space separated)')}
                        </FormLabel>
                        <FormControl>
                          <Input placeholder='bash -lc' {...field} />
                        </FormControl>
                        <FormMessage />
                      </FormItem>
                    )}
                  />

                  <FormField
                    control={form.control}
                    name='args'
                    render={({ field }) => (
                      <FormItem>
                        <FormLabel>{t('Args (space separated)')}</FormLabel>
                        <FormControl>
                          <Input placeholder='--foo bar' {...field} />
                        </FormControl>
                        <FormMessage />
                      </FormItem>
                    )}
                  />
                </div>

                <FormField
                  control={form.control}
                  name='command'
                  render={({ field }) => (
                    <FormItem>
                      <FormLabel>{t('Command')}</FormLabel>
                      <FormControl>
                        <Input placeholder='Optional' {...field} />
                      </FormControl>
                      <FormMessage />
                    </FormItem>
                  )}
                />

                <Collapsible className='rounded-md border p-3'>
                  <CollapsibleTrigger className='cursor-pointer text-sm'>
                    {t('Registry (optional)')}
                  </CollapsibleTrigger>
                  <CollapsibleContent>
                    <div className='mt-3 grid gap-3 md:grid-cols-2 md:gap-4'>
                      <FormField
                        control={form.control}
                        name='registry_username'
                        render={({ field }) => (
                          <FormItem>
                            <FormLabel>{t('Registry username')}</FormLabel>
                            <FormControl>
                              <Input autoComplete='off' {...field} />
                            </FormControl>
                            <FormMessage />
                          </FormItem>
                        )}
                      />
                      <FormField
                        control={form.control}
                        name='registry_secret'
                        render={({ field }) => (
                          <FormItem>
                            <FormLabel>{t('Registry secret')}</FormLabel>
                            <FormControl>
                              <Input
                                type='password'
                                autoComplete='off'
                                {...field}
                              />
                            </FormControl>
                            <FormMessage />
                          </FormItem>
                        )}
                      />
                    </div>
                  </CollapsibleContent>
                </Collapsible>

                <Collapsible className='rounded-md border p-3'>
                  <CollapsibleTrigger className='cursor-pointer text-sm'>
                    {t('Environment variables')}
                  </CollapsibleTrigger>
                  <CollapsibleContent>
                    <div className='mt-3 grid gap-3 md:grid-cols-2 md:gap-4'>
                      <FormField
                        control={form.control}
                        name='env_json'
                        render={({ field }) => (
                          <FormItem>
                            <FormLabel>{t('Env (JSON object)')}</FormLabel>
                            <FormControl>
                              <Textarea
                                className='min-h-40 font-mono text-xs'
                                placeholder='{"KEY":"VALUE"}'
                                {...field}
                              />
                            </FormControl>
                            <FormMessage />
                          </FormItem>
                        )}
                      />
                      <FormField
                        control={form.control}
                        name='secret_env_json'
                        render={({ field }) => (
                          <FormItem>
                            <FormLabel>
                              {t('Secret env (JSON object)')}
                            </FormLabel>
                            <FormControl>
                              <Textarea
                                className='min-h-40 font-mono text-xs'
                                placeholder='{"SECRET":"VALUE"}'
                                {...field}
                              />
                            </FormControl>
                            <FormMessage />
                          </FormItem>
                        )}
                      />
                    </div>
                  </CollapsibleContent>
                </Collapsible>

                <DialogFooter className='grid grid-cols-2 gap-2 pt-2 sm:flex'>
                  <Button
                    type='button'
                    variant='outline'
                    onClick={() => onOpenChange(false)}
                  >
                    {t('Cancel')}
                  </Button>
                  <Button type='submit' disabled={form.formState.isSubmitting}>
                    {form.formState.isSubmitting ? (
                      <Loader2 className='mr-2 h-4 w-4 animate-spin' />
                    ) : null}
                    {t('Update')}
                  </Button>
                </DialogFooter>
              </form>
            </Form>
          </div>
        )}
      </DialogContent>
    </Dialog>
  )
}
