import { useEffect, useMemo, useState } from 'react'

import { Button } from '@/components/ui/button'
import { toast } from '@/components/ui/use-toast'
import { getClientBehaviorSettings, setClientBehaviorSettings } from '@/lib/settings'
import { cn } from '@/lib/utils'

import type { FC, ReactNode } from 'react'

import type { ClientAnimationMode,
	      ClientBehaviorSettings,
	      ClientEmbedAutoLoadMode,
	      ClientLinkPreloadMode,
	      ClientTagRelationDisplayMode } from '@/lib/settings'

type Props = {
    sectionClassName: string
    onDirtyStateChange?: (
	dirty: boolean,
	discard: () => void,
    ) => void }

type SegmentedOption<T extends string> = {
    value: T
    label: string }

type SegmentedControlProps<T extends string> = {
    value:     T
    options:   SegmentedOption<T>[]
    onChange:  (value: T) => void }

type SettingBlockProps = {
    title:        string
    description?: string
    children:     ReactNode }

const animationOptions: SegmentedOption<ClientAnimationMode>[] = [
    { value: 'off', label: 'なし' },
    { value: 'reduced', label: '控えめ' },
    { value: 'normal', label: '通常' }]

const embedAutoLoadOptions: SegmentedOption<ClientEmbedAutoLoadMode>[] = [
    { value: 'off', label: '読み込まない' },
    { value: 'manual', label: 'クリック時' },
    { value: 'auto', label: '自動' }]

const linkPreloadOptions: SegmentedOption<ClientLinkPreloadMode>[] = [
    { value: 'off', label: 'しない' },
    { value: 'intent', label: 'する' }]

const tagRelationDisplayOptions: SegmentedOption<ClientTagRelationDisplayMode>[] = [
    { value: 'flat', label: 'まとめない' },
    { value: 'grouped', label: 'まとめる' }]

const SegmentedControl = <T extends string,> (
    { value, options, onChange }: SegmentedControlProps<T>,
) => {
  return (
      <div
	  role="radiogroup"
	  className="flex flex-wrap gap-2 rounded-xl border border-border bg-muted/40 p-1">
	{options.map (option => (
	    <button
		key={option.value}
		type="button"
		role="radio"
		aria-checked={value === option.value}
		className={cn (
		    'min-w-0 flex-1 rounded-lg px-3 py-2 text-sm font-medium',
		    'transition-colors focus-visible:outline-none focus-visible:ring-2',
		    'focus-visible:ring-ring focus-visible:ring-offset-2',
		    value === option.value
		    ? 'bg-primary text-primary-foreground shadow-sm ring-1 ring-primary/40'
		    : 'bg-transparent text-muted-foreground hover:bg-background/70 hover:text-foreground',
		)}
		onClick={() => onChange (option.value)}>
	      {option.label}
	    </button>))}
      </div>)
}


const SettingBlock: FC<SettingBlockProps> = (
    { title, description, children },
) => (
    <div className="space-y-3 rounded-xl px-4">
      <div className="space-y-1">
	<h3 className="text-sm font-semibold">{title}</h3>
	<p className="text-sm text-muted-foreground">{description}</p>
      </div>
      {children}
    </div>)


const BehaviourSettingsSection: FC<Props> = (
    { sectionClassName,
      onDirtyStateChange },
) => {
  const [savedSettings, setSavedSettings] =
      useState<ClientBehaviorSettings> (() => getClientBehaviorSettings ())
  const [draftSettings, setDraftSettings] =
      useState<ClientBehaviorSettings> (() => getClientBehaviorSettings ())

  useEffect (() => {
    const current = getClientBehaviorSettings ()
    setSavedSettings (current)
    setDraftSettings (current)
  }, [])

  const hasUnsavedChanges = useMemo (
      () => JSON.stringify (draftSettings) !== JSON.stringify (savedSettings),
      [draftSettings, savedSettings])

  const updateDraft = <Key extends keyof ClientBehaviorSettings,> (
      key:    Key,
      value:  ClientBehaviorSettings[Key],
  ) => {
    setDraftSettings (current => ({ ...current, [key]: value }))
  }

  const handleSave = () => {
    const next = setClientBehaviorSettings (draftSettings)
    setSavedSettings (next)
    setDraftSettings (next)
    toast ({ title: '動作設定を保存しました' })
  }

  const handleDiscard = () => {
    setDraftSettings (savedSettings)
  }

  useEffect (() => {
    onDirtyStateChange?.(hasUnsavedChanges, handleDiscard)

    return () => {
      onDirtyStateChange?.(false, () => { })
    }
  }, [handleDiscard, hasUnsavedChanges, onDirtyStateChange])

  return (
      <section className={sectionClassName}>
	<div className="flex flex-wrap items-start justify-between gap-3">
	  <div className="space-y-1">
	    <h2 className="text-xl font-bold">動作</h2>
	  </div>

	  <div className="flex flex-wrap gap-2">
	    <Button
		type="button"
		variant="destructive"
		disabled={hasUnsavedChanges === false}
		onClick={handleDiscard}>
	      変更を破棄
	    </Button>
	    <Button
		type="button"
		disabled={hasUnsavedChanges === false}
		onClick={handleSave}>
	      保存
	    </Button>
	  </div>
	</div>

	<div className="space-y-4">
	  <SettingBlock title="アニメーション">
	    <SegmentedControl
		value={draftSettings.animation ?? 'normal'}
		options={animationOptions}
		onChange={value => updateDraft ('animation', value)}/>
	  </SettingBlock>

	  <SettingBlock
	      title="リンク先の先読み"
	      description="マウスを置いた時点でリンク先のデータを取得します。">
	    <SegmentedControl
		value={draftSettings.linkPreload ?? 'intent'}
		options={linkPreloadOptions}
		onChange={value => updateDraft ('linkPreload', value)}/>
	  </SettingBlock>

	  <SettingBlock title="タグの親子関係表示">
	    <SegmentedControl
		value={draftSettings.tagRelationDisplay ?? 'grouped'}
		options={tagRelationDisplayOptions}
		onChange={value => updateDraft ('tagRelationDisplay', value)}/>
	  </SettingBlock>

	  <SettingBlock title="埋め込み自動読込">
	    <SegmentedControl
		value={draftSettings.embedAutoLoad ?? 'auto'}
		options={embedAutoLoadOptions}
		onChange={value => updateDraft ('embedAutoLoad', value)}/>
	  </SettingBlock>
	</div>
      </section>)
}

export default BehaviourSettingsSection
