import {
  Field,
  Input,
  Switch,
  Checkbox,
  Caption1,
  makeStyles,
  tokens
} from '@fluentui/react-components'
import {
  AUDIO_FORMATS,
  VIDEO_CONTAINERS,
  VIDEO_CODECS,
  SPONSORBLOCK_CATEGORIES,
  type AudioFormat,
  type VideoContainer,
  type VideoCodecPref,
  type SponsorBlockMode,
  type SponsorBlockCategory,
  type DownloadOptions
} from '@shared/ipc'
import { Select } from './Select'

// Human labels for the format/category enums.
const AUDIO_FORMAT_LABELS: Record<AudioFormat, string> = {
  best: 'Best (keep source)',
  mp3: 'MP3',
  m4a: 'M4A (AAC)',
  opus: 'Opus',
  flac: 'FLAC (lossless)',
  wav: 'WAV (lossless)',
  aac: 'AAC'
}
const VIDEO_CONTAINER_LABELS: Record<VideoContainer, string> = {
  mp4: 'MP4',
  mkv: 'MKV',
  webm: 'WebM'
}
const VIDEO_CODEC_LABELS: Record<VideoCodecPref, string> = {
  any: 'No preference',
  h264: 'H.264 (most compatible)',
  vp9: 'VP9',
  av1: 'AV1 (smallest)'
}
const SPONSORBLOCK_LABELS: Record<SponsorBlockCategory, string> = {
  sponsor: 'Sponsor',
  intro: 'Intro / intermission',
  outro: 'End cards / credits',
  selfpromo: 'Self-promotion',
  preview: 'Preview / recap',
  filler: 'Filler / tangent',
  interaction: 'Interaction reminder',
  music_offtopic: 'Non-music section'
}

const useStyles = makeStyles({
  root: {
    display: 'flex',
    flexDirection: 'column',
    gap: '16px'
  },
  grid: {
    display: 'grid',
    gridTemplateColumns: 'repeat(auto-fit, minmax(170px, 1fr))',
    gap: '16px'
  },
  // Indented reveal for options that only matter when their parent is enabled.
  subGroup: {
    display: 'flex',
    flexDirection: 'column',
    gap: '12px',
    paddingLeft: '14px',
    borderLeft: `2px solid ${tokens.colorNeutralStroke2}`
  },
  categoryGrid: {
    display: 'grid',
    gridTemplateColumns: '1fr 1fr',
    columnGap: '16px',
    rowGap: '2px'
  }
})

interface Props {
  value: DownloadOptions
  onChange: (next: DownloadOptions) => void
  /** When provided, hides controls that don't apply to this media kind. */
  kind?: 'video' | 'audio'
}

/**
 * The full set of post-processing controls, driven by a DownloadOptions value.
 * Used both for the persisted defaults (Settings) and for a per-download
 * override (the download bar), so the two never drift apart.
 */
export function DownloadOptionsForm({ value, onChange, kind }: Props): React.JSX.Element {
  const styles = useStyles()

  function setOpt<K extends keyof DownloadOptions>(key: K, v: DownloadOptions[K]): void {
    onChange({ ...value, [key]: v })
  }

  function toggleCategory(cat: SponsorBlockCategory, on: boolean): void {
    const next = on
      ? [...value.sponsorBlockCategories, cat]
      : value.sponsorBlockCategories.filter((c) => c !== cat)
    setOpt('sponsorBlockCategories', next)
  }

  return (
    <div className={styles.root}>
      <div className={styles.grid}>
        {kind !== 'video' && (
          <Field label="Audio format" hint="For audio-only downloads.">
            <Select
              value={value.audioFormat}
              options={AUDIO_FORMATS.map((f) => ({ value: f, label: AUDIO_FORMAT_LABELS[f] }))}
              onChange={(v) => setOpt('audioFormat', v as AudioFormat)}
            />
          </Field>
        )}
        {kind !== 'audio' && (
          <Field
            label="Video container"
            hint="The file format used when video and audio are combined into one file."
          >
            <Select
              value={value.videoContainer}
              options={VIDEO_CONTAINERS.map((c) => ({
                value: c,
                label: VIDEO_CONTAINER_LABELS[c]
              }))}
              onChange={(v) => setOpt('videoContainer', v as VideoContainer)}
            />
          </Field>
        )}
        {kind !== 'audio' && (
          <Field
            label="Preferred codec"
            hint="A preference when several formats match -- not a strict filter."
          >
            <Select
              value={value.preferredVideoCodec}
              options={VIDEO_CODECS.map((c) => ({ value: c, label: VIDEO_CODEC_LABELS[c] }))}
              onChange={(v) => setOpt('preferredVideoCodec', v as VideoCodecPref)}
            />
          </Field>
        )}
      </div>

      <Field
        label="Format sorting (advanced)"
        hint="Custom expression to rank available formats, e.g. res:1080,vcodec:av01,size. Leave blank to use the Preferred codec setting above. See yt-dlp docs for the full syntax."
      >
        <Input
          value={value.formatSort}
          placeholder="res,fps,vcodec:av01"
          onChange={(_, d) => setOpt('formatSort', d.value)}
        />
      </Field>

      <Field label="Embed subtitles" hint="Download subtitles and embed them in the video file.">
        <Switch
          checked={value.embedSubtitles}
          onChange={(_, d) => setOpt('embedSubtitles', d.checked)}
        />
      </Field>
      {value.embedSubtitles && (
        <div className={styles.subGroup}>
          <Field
            label="Subtitle languages"
            hint="Comma-separated, e.g. en, es. Use a pattern like en.* to include regional variants."
          >
            <Input
              value={value.subtitleLanguages}
              onChange={(_, d) => setOpt('subtitleLanguages', d.value)}
            />
          </Field>
          <Checkbox
            checked={value.autoSubtitles}
            onChange={(_, d) => setOpt('autoSubtitles', !!d.checked)}
            label="Also include auto-generated captions"
          />
        </div>
      )}

      <Field
        label="SponsorBlock"
        hint="Skip or label sponsor and other segments using the SponsorBlock database."
      >
        <Switch
          checked={value.sponsorBlock}
          onChange={(_, d) => setOpt('sponsorBlock', d.checked)}
        />
      </Field>
      {value.sponsorBlock && (
        <div className={styles.subGroup}>
          <Field label="Action">
            <Select
              value={value.sponsorBlockMode}
              options={[
                { value: 'remove', label: 'Remove segments (cut from file)' },
                { value: 'mark', label: 'Mark as chapters (keep, but labelled)' }
              ]}
              onChange={(v) => setOpt('sponsorBlockMode', v as SponsorBlockMode)}
            />
          </Field>
          <Field
            label="Categories"
            validationState={value.sponsorBlockCategories.length === 0 ? 'warning' : 'none'}
            validationMessage={
              value.sponsorBlockCategories.length === 0
                ? 'No categories selected -- no segments will be skipped.'
                : undefined
            }
          >
            <div className={styles.categoryGrid}>
              {SPONSORBLOCK_CATEGORIES.map((cat) => (
                <Checkbox
                  key={cat}
                  checked={value.sponsorBlockCategories.includes(cat)}
                  onChange={(_, d) => toggleCategory(cat, !!d.checked)}
                  label={SPONSORBLOCK_LABELS[cat]}
                />
              ))}
            </div>
          </Field>
        </div>
      )}

      <Field
        label="Embed chapters"
        hint="Write chapter markers into the file. Only useful if the video has chapters."
      >
        <Switch
          checked={value.embedChapters}
          onChange={(_, d) => setOpt('embedChapters', d.checked)}
        />
      </Field>
      <Field
        label="Split by chapters"
        hint="Also save each chapter as its own file. The full-length file is kept too."
      >
        <Switch
          checked={value.splitChapters}
          onChange={(_, d) => setOpt('splitChapters', d.checked)}
        />
      </Field>
      <Field label="Embed metadata" hint="Title, artist, date and similar tags.">
        <Switch
          checked={value.embedMetadata}
          onChange={(_, d) => setOpt('embedMetadata', d.checked)}
        />
      </Field>
      <Field
        label="Metadata overrides"
        hint="Override specific tags before embedding. Leave blank to keep the extracted value. Automatically enables embed metadata."
      >
        <div className={styles.subGroup}>
          <Input
            placeholder="Title"
            value={value.metadataTitle ?? ''}
            onChange={(_, d) => setOpt('metadataTitle', d.value)}
          />
          <Input
            placeholder="Artist"
            value={value.metadataArtist ?? ''}
            onChange={(_, d) => setOpt('metadataArtist', d.value)}
          />
          <Input
            placeholder="Album"
            value={value.metadataAlbum ?? ''}
            onChange={(_, d) => setOpt('metadataAlbum', d.value)}
          />
        </div>
      </Field>
      <Field label="Embed thumbnail" hint="Cover art for audio; poster frame for MP4/MKV.">
        <Switch
          checked={value.embedThumbnail}
          onChange={(_, d) => setOpt('embedThumbnail', d.checked)}
        />
      </Field>
      {value.embedThumbnail && (
        <div className={styles.subGroup}>
          <Checkbox
            checked={value.cropThumbnail}
            onChange={(_, d) => setOpt('cropThumbnail', !!d.checked)}
            label="Crop audio artwork to a square"
          />
          <Caption1 style={{ color: tokens.colorNeutralForeground3 }}>
            Squares the embedded cover for audio files.
          </Caption1>
        </div>
      )}

      <Field
        label="Sidecar files"
        hint="Write separate metadata/poster/description files next to each download -- handy for Jellyfin, Plex or Kodi libraries."
      >
        <div className={styles.subGroup}>
          <Checkbox
            checked={value.writeInfoJson}
            onChange={(_, d) => setOpt('writeInfoJson', !!d.checked)}
            label="Metadata (.info.json)"
          />
          <Checkbox
            checked={value.writeThumbnailFile}
            onChange={(_, d) => setOpt('writeThumbnailFile', !!d.checked)}
            label="Thumbnail image file"
          />
          <Checkbox
            checked={value.writeDescription}
            onChange={(_, d) => setOpt('writeDescription', !!d.checked)}
            label="Description (.description)"
          />
        </div>
      </Field>
    </div>
  )
}
