import { useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useQueryClient } from '@tanstack/react-query';
import { HelpText } from './HelpText';
import { FieldLabel, FieldInput } from './formUtils';
import type { SectionFormProps } from './types';

type AssetKind = 'logo' | 'favicon';

const ACCEPT: Record<AssetKind, string> = {
  logo: '.svg,.png,.jpg,.jpeg,.webp,.gif',
  favicon: '.svg,.png,.ico,.webp',
};

const MAX_SIZE: Record<AssetKind, number> = {
  logo: 2 * 1024 * 1024,
  favicon: 256 * 1024,
};

async function fileToBase64(file: File): Promise<string> {
  const buf = await file.arrayBuffer();
  // btoa does not accept non-ASCII; convert via chunked construction.
  let binary = '';
  const bytes = new Uint8Array(buf);
  const chunk = 0x8000;
  for (let i = 0; i < bytes.length; i += chunk) {
    binary += String.fromCharCode(...bytes.subarray(i, i + chunk));
  }
  return btoa(binary);
}

function AssetUploader({
  kind,
  currentUrl,
  onChanged,
}: {
  kind: AssetKind;
  currentUrl: string | null;
  /** Called after a successful upload/delete with the new URL (null when cleared). */
  onChanged: (newUrl: string | null) => void;
}) {
  const { t } = useTranslation('settings');
  const fileRef = useRef<HTMLInputElement | null>(null);
  const [busy, setBusy] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const handlePick = () => fileRef.current?.click();

  const handleFile = async (file: File) => {
    setError(null);
    if (file.size > MAX_SIZE[kind]) {
      setError(t('branding.sizeExceeded', { kb: Math.round(MAX_SIZE[kind] / 1024) }));
      return;
    }
    try {
      setBusy(true);
      const contentBase64 = await fileToBase64(file);
      const res = await fetch('/api/branding/upload', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ kind, filename: file.name, contentBase64 }),
      });
      const body = await res.json().catch(() => ({}));
      if (!res.ok) {
        throw new Error(body.error ?? t('branding.uploadFailed', { status: res.status }));
      }
      onChanged(typeof body.url === 'string' ? body.url : null);
    } catch (e) {
      setError(e instanceof Error ? e.message : String(e));
    } finally {
      setBusy(false);
      if (fileRef.current) fileRef.current.value = '';
    }
  };

  const handleClear = async () => {
    setError(null);
    try {
      setBusy(true);
      const res = await fetch(`/api/branding/upload?kind=${kind}`, { method: 'DELETE' });
      if (!res.ok) throw new Error(t('branding.deleteFailed', { status: res.status }));
      onChanged(null);
    } catch (e) {
      setError(e instanceof Error ? e.message : String(e));
    } finally {
      setBusy(false);
    }
  };

  return (
    <div>
      <div className="flex items-center gap-3">
        <div
          className={`h-12 w-12 flex-shrink-0 rounded-md border border-hairline bg-surface flex items-center justify-center overflow-hidden ${
            kind === 'favicon' ? 'bg-canvas' : ''
          }`}
        >
          {currentUrl ? (
            <img src={currentUrl} alt="" className="h-full w-full object-contain" />
          ) : (
            <span className="text-[10px] text-slate-400">{t('branding.notSet')}</span>
          )}
        </div>
        <div className="flex-1 min-w-0">
          <input
            ref={fileRef}
            type="file"
            accept={ACCEPT[kind]}
            className="hidden"
            onChange={e => {
              const f = e.target.files?.[0];
              if (f) void handleFile(f);
            }}
          />
          <div className="flex gap-1.5">
            <button
              type="button"
              onClick={handlePick}
              disabled={busy}
              className="px-2.5 h-7 text-2xs font-medium bg-canvas border border-hairline rounded-md text-slate-700 hover:bg-surface disabled:opacity-50 transition-colors"
            >
              {currentUrl ? t('branding.replace') : t('branding.upload')}
            </button>
            {currentUrl && (
              <button
                type="button"
                onClick={() => void handleClear()}
                disabled={busy}
                className="px-2.5 h-7 text-2xs font-medium text-red-700 dark:text-red-300 border border-red-200 bg-canvas hover:bg-red-50 dark:hover:bg-red-500/15 rounded-md disabled:opacity-50 transition-colors"
              >
                {t('branding.delete')}
              </button>
            )}
          </div>
          <div className="text-[10px] text-slate-400 mt-1 truncate font-mono">
            {currentUrl ?? t('branding.accept', { accept: ACCEPT[kind], kb: Math.round(MAX_SIZE[kind] / 1024) })}
          </div>
        </div>
      </div>
      {error && <div className="mt-1.5 text-2xs text-red-600">⚠ {error}</div>}
    </div>
  );
}

export function BrandingForm({ config, onChange }: SectionFormProps) {
  const { t } = useTranslation('settings');
  const branding = config.branding ?? {};
  const primaryColor = branding.primaryColor ?? '';
  const qc = useQueryClient();

  // サーバーは upload 時に config.yaml を直接書き換える。
  // ローカル draft も同期して、他フィールドの編集中でも整合を保つ。
  const handleAssetChange = (field: 'logoUrl' | 'faviconUrl') => (newUrl: string | null) => {
    onChange(`branding.${field}`, newUrl ?? '');
    // Branding API (TopBar の画像など) は別クエリなので個別に再取得
    void qc.invalidateQueries({ queryKey: ['branding'] });
  };

  return (
    <div className="space-y-5">
      <h2 className="text-base font-semibold text-slate-800">{t('branding.title')}</h2>
      <p className="text-xs text-slate-500 -mt-3">
        {t('branding.intro')}
      </p>

      <div>
        <FieldLabel>{t('branding.appName')}</FieldLabel>
        <FieldInput
          value={branding.appName ?? ''}
          onChange={v => onChange('branding.appName', v)}
          placeholder="MAESTRO"
        />
        <HelpText>{t('branding.appNameHelp')}</HelpText>
      </div>

      <div>
        <FieldLabel>{t('branding.primaryColor')}</FieldLabel>
        <div className="flex items-center gap-2">
          <input
            type="color"
            value={primaryColor || '#2563eb'}
            onChange={e => onChange('branding.primaryColor', e.target.value)}
            className="h-9 w-12 rounded border border-slate-300 p-0 cursor-pointer"
            aria-label={t('branding.primaryColor')}
          />
          <input
            type="text"
            value={primaryColor}
            onChange={e => onChange('branding.primaryColor', e.target.value)}
            placeholder="#2563eb"
            className="flex-1 px-3 py-2 text-sm font-mono border border-slate-300 rounded-lg focus:ring-2 focus:ring-accent-ring focus:border-accent outline-none"
          />
        </div>
        <HelpText>{t('branding.primaryColorHelp')}</HelpText>
      </div>

      <div>
        <FieldLabel>{t('branding.loginTitle')}</FieldLabel>
        <FieldInput
          value={branding.loginPageTitle ?? ''}
          onChange={v => onChange('branding.loginPageTitle', v)}
          placeholder="MAESTRO"
        />
        <HelpText>{t('branding.loginTitleHelp')}</HelpText>
      </div>

      <div>
        <FieldLabel>{t('branding.logo')}</FieldLabel>
        <AssetUploader
          kind="logo"
          currentUrl={branding.logoUrl || null}
          onChanged={handleAssetChange('logoUrl')}
        />
        <HelpText>{t('branding.logoHelp')}</HelpText>
      </div>

      <div>
        <FieldLabel>{t('branding.favicon')}</FieldLabel>
        <AssetUploader
          kind="favicon"
          currentUrl={branding.faviconUrl || null}
          onChanged={handleAssetChange('faviconUrl')}
        />
        <HelpText>{t('branding.faviconHelp')}</HelpText>
      </div>

      <div>
        <FieldLabel>{t('branding.footer')}</FieldLabel>
        <FieldInput
          value={branding.footerText ?? ''}
          onChange={v => onChange('branding.footerText', v)}
          placeholder="© 2026 Your Team"
        />
        <HelpText>{t('branding.footerHelp')}</HelpText>
      </div>
    </div>
  );
}
