import PostOriginalCreatedTimeField from '@/components/PostOriginalCreatedTimeField'
import FieldError from '@/components/common/FieldError'
import FieldWarning from '@/components/common/FieldWarning'
import FormField from '@/components/common/FormField'
import PostImportStatusBadge from '@/components/posts/import/PostImportStatusBadge'
import ThumbnailPreview from '@/components/posts/import/ThumbnailPreview'
import { effectivePostImportStatus } from '@/components/posts/import/postImportRowStatus'
import { Button } from '@/components/ui/button'
import { Dialog,
	 DialogContent,
	 DialogDescription,
	 DialogFooter,
	 DialogHeader,
	 DialogTitle } from '@/components/ui/dialog'
import { inputClass } from '@/lib/utils'

import type { FC } from 'react'
import { useEffect, useState } from 'react'

import type { PostImportOrigin,
	      PostImportRow } from '@/lib/postImportSession'

type Draft = {
    url:                   string
    title:                 string
    thumbnailBase:         string
    originalCreatedFrom:   string
    originalCreatedBefore: string
    duration:              string
    tags:                  string
    parentPostIds:         string }

type Props = {
    open:         boolean
    row:          PostImportRow | null
    saving:       boolean
    onOpenChange: (open: boolean) => void
    onSave:       (draft: Draft) => Promise<boolean> }

const originOf = (
    row:   PostImportRow,
    field: string,
): PostImportOrigin =>
    row.provenance[field] ?? 'automatic'

const originalCreatedOrigin = (row: PostImportRow): PostImportOrigin =>
    originOf (row, 'originalCreatedFrom') === 'manual'
    || originOf (row, 'originalCreatedBefore') === 'manual'
    ? 'manual'
    : 'automatic'

const buildDraft = (row: PostImportRow): Draft => ({
    url: row.url,
    title: String (row.attributes.title ?? ''),
    thumbnailBase: String (row.attributes.thumbnailBase ?? ''),
    originalCreatedFrom: String (row.attributes.originalCreatedFrom ?? ''),
    originalCreatedBefore: String (row.attributes.originalCreatedBefore ?? ''),
    duration: String (row.attributes.duration ?? ''),
    tags: String (row.attributes.tags ?? ''),
    parentPostIds: String (row.attributes.parentPostIds ?? '') })

const groupedMessages = (
    ...values: Array<string[] | undefined>
): string[] =>
    values.flatMap (value => value ?? [])


const PostImportRowDialog: FC<Props> = (
    { open, row, saving, onOpenChange, onSave },
) => {
    const [draft, setDraft] = useState<Draft | null> (null)

    useEffect (() => {
	if (open && row)
	  setDraft (buildDraft (row))
    }, [open, row])

    if (!(row) || !(draft))
      return null

    const update = <Key extends keyof Draft,> (
	key:   Key,
	value: Draft[Key],
    ) => {
	setDraft (current =>
	    current ? { ...current, [key]: value } : current)
    }

    const save = async () => {
	if (await onSave (draft))
	  onOpenChange (false)
    }

    return (
	<Dialog open={open} onOpenChange={onOpenChange}>
	  <DialogContent className="flex max-h-[calc(100dvh-1rem)] max-w-3xl flex-col
				   overflow-hidden p-0">
	    <DialogHeader className="shrink-0 px-6 pb-4 pt-7">
	      <DialogTitle>投稿を編輯</DialogTitle>
	      <DialogDescription>
		投稿 {row.sourceRow} の内容を確認し、必要な項目を編輯してください．
	      </DialogDescription>
	    </DialogHeader>

	    <div className="min-h-0 flex-1 overflow-y-auto overscroll-contain px-6 pb-6">
	      <div className="grid gap-6 md:grid-cols-[7rem_minmax(0,1fr)]">
		<div className="space-y-3">
		  <ThumbnailPreview
		      url={draft.thumbnailBase}
		      className="h-28 w-28"/>
		  <div className="flex flex-wrap gap-2">
		    <PostImportStatusBadge value={effectivePostImportStatus (row)}/>
		  </div>
		</div>

		<div className="space-y-4">
		  <DialogTextField
		      label="URL"
		      value={draft.url}
		      origin={originOf (row, 'url')}
		      warnings={row.fieldWarnings.url}
		      errors={groupedMessages (row.validationErrors.url, row.importErrors?.url)}
		      onChange={value => update ('url', value)}/>
		  <DialogTextField
		      label="タイトル"
		      value={draft.title}
		      origin={originOf (row, 'title')}
		      warnings={row.fieldWarnings.title}
		      errors={groupedMessages (row.validationErrors.title, row.importErrors?.title)}
		      onChange={value => update ('title', value)}/>
		  <DialogTextField
		      label="サムネール基底 URL"
		      value={draft.thumbnailBase}
		      origin={originOf (row, 'thumbnailBase')}
		      warnings={row.fieldWarnings.thumbnailBase}
		      errors={groupedMessages (
			  row.validationErrors.thumbnailBase,
			  row.importErrors?.thumbnailBase,
		      )}
		      onChange={value => update ('thumbnailBase', value)}/>
		  <PostOriginalCreatedTimeField
		      labelAddon={<PostImportStatusBadge value={originalCreatedOrigin (row)}/>}
		      originalCreatedFrom={draft.originalCreatedFrom || null}
		      setOriginalCreatedFrom={value => update ('originalCreatedFrom', value ?? '')}
		      originalCreatedBefore={draft.originalCreatedBefore || null}
		      setOriginalCreatedBefore={value => update ('originalCreatedBefore', value ?? '')}
		      errors={groupedMessages (
			  row.validationErrors.originalCreatedAt,
			  row.validationErrors.originalCreatedFrom,
			  row.validationErrors.originalCreatedBefore,
			  row.importErrors?.originalCreatedAt,
			  row.importErrors?.originalCreatedFrom,
			  row.importErrors?.originalCreatedBefore,
		      )}/>
		  <DialogTextField
		      label="動画時間"
		      value={draft.duration}
		      origin={originOf (row, 'duration')}
		      errors={groupedMessages (
			  row.validationErrors.duration,
			  row.validationErrors.videoMs,
			  row.importErrors?.duration,
			  row.importErrors?.videoMs,
		      )}
		      onChange={value => update ('duration', value)}/>
		  <DialogAreaField
		      label="タグ"
		      value={draft.tags}
		      origin={originOf (row, 'tags')}
		      warnings={row.fieldWarnings.tags}
		      errors={groupedMessages (row.validationErrors.tags, row.importErrors?.tags)}
		      onChange={value => update ('tags', value)}/>
		  <DialogTextField
		      label="親投稿"
		      value={draft.parentPostIds}
		      origin={originOf (row, 'parentPostIds')}
		      errors={groupedMessages (
			  row.validationErrors.parentPostIds,
			  row.importErrors?.parentPostIds,
		      )}
		      onChange={value => update ('parentPostIds', value)}/>
		  <FieldWarning messages={row.baseWarnings}/>
		  <FieldError messages={row.validationErrors.base}/>
		  <FieldError messages={row.importErrors?.base}/>
		</div>
	      </div>
	    </div>

	    <DialogFooter className="shrink-0 px-6 pb-6 pt-4">
	      <Button
		  type="button"
		  variant="outline"
		  onClick={() => onOpenChange (false)}>
		取消し
	      </Button>
	      <Button
		  type="button"
		  onClick={save}
		  disabled={saving}>
		編輯内容を保存
	      </Button>
	    </DialogFooter>
	  </DialogContent>
	</Dialog>)
}

const DialogTextField = (
    { label, value, origin, warnings, errors, onChange }: {
	label:    string
	value:    string
	origin:   PostImportOrigin
	warnings?: string[]
	errors?:   string[]
	onChange: (value: string) => void },
) => (
    <FormField label={<DialogLabel label={label} origin={origin}/>} messages={errors}>
      {({ describedBy, invalid }) => (
	  <>
	    <input
		value={value}
		onChange={ev => onChange (ev.target.value)}
		aria-describedby={describedBy}
		aria-invalid={invalid}
		className={inputClass (invalid)}/>
	    <FieldWarning messages={warnings}/>
	  </>)}
    </FormField>)

const DialogAreaField = (
    { label, value, origin, warnings, errors, onChange }: {
	label:    string
	value:    string
	origin:   PostImportOrigin
	warnings?: string[]
	errors?:   string[]
	onChange: (value: string) => void },
) => (
    <FormField label={<DialogLabel label={label} origin={origin}/>} messages={errors}>
      {({ describedBy, invalid }) => (
	  <>
	    <textarea
		value={value}
		rows={4}
		onChange={ev => onChange (ev.target.value)}
		aria-describedby={describedBy}
		aria-invalid={invalid}
		className={inputClass (invalid)}/>
	    <FieldWarning messages={warnings}/>
	  </>)}
    </FormField>)

const DialogLabel = (
    { label, origin }: {
	label:   string
	origin:  PostImportOrigin },
) => (
    <span className="flex items-center gap-2">
      <span>{label}</span>
      <PostImportStatusBadge value={origin}/>
    </span>)

export default PostImportRowDialog
