import { useEffect, useMemo, useState } from 'react';
import * as Dialog from '@radix-ui/react-dialog';
import { ArrowLeft, Bell, Pencil, Plus, Save, Trash2 } from 'lucide-react';
import { request } from '../api/client.js';
import { ConfirmDialog } from '../components/ConfirmDialog.jsx';
import { Field } from '../components/Field.jsx';
import { useToast } from '../components/Toast.jsx';

const unitToHours = {
  hours: 1,
  days: 24,
  weeks: 168,
};

function toDisplayThreshold(thresholdHours) {
  if (thresholdHours % unitToHours.weeks === 0) {
    return { value: thresholdHours / unitToHours.weeks, unit: 'weeks' };
  }
  if (thresholdHours % unitToHours.days === 0) {
    return { value: thresholdHours / unitToHours.days, unit: 'days' };
  }
  return { value: thresholdHours, unit: 'hours' };
}

function toThresholdHours(condition) {
  const value = String(condition.value).trim();
  if (!/^\d+$/.test(value)) return Number.NaN;
  return Number.parseInt(value, 10) * unitToHours[condition.unit];
}

function formatCertificateValue(value) {
  if (!value) return '未取得';
  const date = new Date(value);
  if (Number.isNaN(date.getTime())) return '未取得';
  return date.toLocaleString();
}

function formatCondition(condition) {
  const unitLabels = {
    hours: '時間前',
    days: '日前',
    weeks: '週間前',
  };
  return `${condition.value}${unitLabels[condition.unit]}`;
}

export function SiteSettingsPanel({ site, onBack }) {
  const [alias, setAlias] = useState(site.alias);
  const [savedAlias, setSavedAlias] = useState(site.alias);
  const [conditions, setConditions] = useState([]);
  const [timingDialogOpen, setTimingDialogOpen] = useState(false);
  const [editingConditionIndex, setEditingConditionIndex] = useState(null);
  const [timingForm, setTimingForm] = useState({ value: '', unit: 'days' });
  const [availableWebhooks, setAvailableWebhooks] = useState([]);
  const [webhookMethodIds, setWebhookMethodIds] = useState([]);
  const [pushEnabled, setPushEnabled] = useState(false);
  const [busy, setBusy] = useState(false);
  const { showToast } = useToast();

  const previewText = useMemo(() => {
    const hours = conditions
      .map(toThresholdHours)
      .filter((value) => Number.isInteger(value) && value > 0)
      .sort((a, b) => a - b);
    if (hours.length === 0) return '通知タイミング未設定';
    return hours.map((hour) => `${hour} 時間前`).join(' / ');
  }, [conditions]);

  useEffect(() => {
    setAlias(site.alias);
    setSavedAlias(site.alias);
  }, [site.alias, site.siteId]);

  useEffect(() => {
    async function loadSettings() {
      const data = await request(`/api/sites/${site.siteId}/settings`);
      setAvailableWebhooks(data.settings.availableWebhooks);
      if (data.settings.conditions.length > 0) {
        setConditions(
          data.settings.conditions.map((condition) => toDisplayThreshold(condition.thresholdHours)),
        );
        setWebhookMethodIds(data.settings.conditions[0].webhookMethodIds);
        setPushEnabled(data.settings.conditions[0].pushEnabled);
      } else {
        setConditions([]);
        setWebhookMethodIds([]);
        setPushEnabled(false);
      }
    }
    loadSettings().catch((err) => showToast({ type: 'error', message: err.message }));
  }, [showToast, site.siteId]);

  function openAddConditionDialog() {
    setEditingConditionIndex(null);
    setTimingForm({ value: '', unit: 'days' });
    setTimingDialogOpen(true);
  }

  function openEditConditionDialog(index) {
    setEditingConditionIndex(index);
    setTimingForm({
      value: String(conditions[index].value),
      unit: conditions[index].unit,
    });
    setTimingDialogOpen(true);
  }

  function saveTimingCondition(event) {
    event.preventDefault();
    event.stopPropagation();

    const thresholdHours = toThresholdHours(timingForm);
    if (!Number.isInteger(thresholdHours) || thresholdHours <= 0 || thresholdHours > 17520) {
      showToast({
        type: 'error',
        message: '通知タイミングは 1 時間以上、2 年以内で指定してください',
      });
      return;
    }

    const duplicated = conditions.some((condition, index) => {
      if (index === editingConditionIndex) return false;
      return toThresholdHours(condition) === thresholdHours;
    });
    if (duplicated) {
      showToast({ type: 'error', message: '同じ通知タイミングは重複して登録できません' });
      return;
    }

    setConditions((current) => {
      const nextCondition = {
        value: Number.parseInt(String(timingForm.value).trim(), 10),
        unit: timingForm.unit,
      };
      if (editingConditionIndex === null) {
        return [...current, nextCondition];
      }
      return current.map((condition, index) =>
        index === editingConditionIndex ? nextCondition : condition,
      );
    });
    setTimingDialogOpen(false);
  }

  function removeCondition(index) {
    setConditions((current) => current.filter((_, currentIndex) => currentIndex !== index));
  }

  function toggleWebhook(methodId) {
    setWebhookMethodIds((current) =>
      current.includes(methodId) ? current.filter((id) => id !== methodId) : [...current, methodId],
    );
  }

  async function saveSettings(event) {
    event.preventDefault();
    setBusy(true);
    try {
      const nextAlias = alias.trim();
      if (!nextAlias) {
        throw new Error('エイリアス名を入力してください');
      }
      if (nextAlias.length > 120) {
        throw new Error('エイリアス名は120文字以内で入力してください');
      }
      const thresholdHours = conditions.map(toThresholdHours);
      if (thresholdHours.some((value) => !Number.isInteger(value) || value <= 0 || value > 17520)) {
        throw new Error('通知タイミングは 1 時間以上、2 年以内で指定してください');
      }
      if (new Set(thresholdHours).size !== thresholdHours.length) {
        throw new Error('同じ通知タイミングは重複して登録できません');
      }
      if (nextAlias !== savedAlias) {
        await request(`/api/sites/${site.siteId}`, {
          method: 'PATCH',
          body: JSON.stringify({ alias: nextAlias }),
        });
        setAlias(nextAlias);
        setSavedAlias(nextAlias);
      }
      if (thresholdHours.length === 0) {
        await request(`/api/sites/${site.siteId}/settings`, { method: 'DELETE' });
        setWebhookMethodIds([]);
        setPushEnabled(false);
      } else {
        await request(`/api/sites/${site.siteId}/settings`, {
          method: 'PUT',
          body: JSON.stringify({
            conditions: thresholdHours.map((value) => ({ thresholdHours: value })),
            webhookMethodIds,
            pushEnabled,
          }),
        });
      }
      showToast({ type: 'success', message: '設定を保存しました' });
    } catch (err) {
      showToast({ type: 'error', message: err.message });
    } finally {
      setBusy(false);
    }
  }

  async function deleteSettings() {
    setBusy(true);
    try {
      await request(`/api/sites/${site.siteId}/settings`, { method: 'DELETE' });
      setConditions([]);
      setWebhookMethodIds([]);
      setPushEnabled(false);
      showToast({ type: 'success', message: '設定を削除しました' });
    } catch (err) {
      showToast({ type: 'error', message: err.message });
    } finally {
      setBusy(false);
    }
  }

  return (
    <main className="app-shell">
      <header className="topbar">
        <button className="back-button" onClick={onBack}>
          <ArrowLeft aria-hidden="true" size={18} />
          サイト一覧
        </button>
        <div className="settings-title">
          <span className="eyebrow">サイト設定</span>
          <h1>{savedAlias}</h1>
          <p>{site.url}</p>
        </div>
      </header>

      <section className="workspace settings-layout">
        <form className="settings-form" onSubmit={saveSettings}>
          <section className="panel">
            <h2>基本情報</h2>
            <Field label="エイリアス名">
              <input
                value={alias}
                onChange={(event) => setAlias(event.target.value)}
                maxLength="120"
                required
              />
            </Field>
          </section>

          <section className="panel">
            <h2>証明書情報</h2>
            <dl className="certificate-details">
              <div>
                <dt>発行元</dt>
                <dd>{site.certificateIssuer || '未取得'}</dd>
              </div>
              <div>
                <dt>発行日時</dt>
                <dd>{formatCertificateValue(site.certificateIssuedAt)}</dd>
              </div>
              <div>
                <dt>失効日時</dt>
                <dd>{formatCertificateValue(site.certificateExpiresAt)}</dd>
              </div>
            </dl>
          </section>

          <section className="panel">
            <div className="panel-heading">
              <Bell aria-hidden="true" size={20} />
              <div>
                <h2>通知タイミング</h2>
                <p>{previewText}</p>
              </div>
            </div>

            <div className="condition-list">
              {conditions.length === 0 ? (
                <p className="condition-empty">通知タイミングはまだ設定されていません。</p>
              ) : (
                conditions.map((condition, index) => (
                  <div
                    className="condition-row"
                    key={`${condition.unit}-${condition.value}-${index}`}
                  >
                    <span className="condition-value">{formatCondition(condition)}</span>
                    <div className="condition-actions">
                      <button
                        type="button"
                        className="icon-button"
                        onClick={() => openEditConditionDialog(index)}
                        aria-label="通知タイミングを編集"
                        title="編集"
                      >
                        <Pencil aria-hidden="true" size={18} />
                      </button>
                      <ConfirmDialog
                        title="通知タイミングを削除"
                        description="この通知タイミングを設定から削除します。"
                        onConfirm={() => removeCondition(index)}
                        trigger={
                          <button
                            type="button"
                            className="icon-button danger"
                            aria-label="通知タイミングを削除"
                            title="削除"
                          >
                            <Trash2 aria-hidden="true" size={18} />
                          </button>
                        }
                      />
                    </div>
                  </div>
                ))
              )}
            </div>

            <button type="button" className="secondary" onClick={openAddConditionDialog}>
              <Plus aria-hidden="true" size={18} />
              タイミングを追加
            </button>

            <Dialog.Root open={timingDialogOpen} onOpenChange={setTimingDialogOpen}>
              <Dialog.Portal>
                <Dialog.Overlay className="dialog-overlay" />
                <Dialog.Content className="dialog-content">
                  <Dialog.Title className="dialog-title">
                    {editingConditionIndex === null
                      ? '通知タイミングを追加'
                      : '通知タイミングを編集'}
                  </Dialog.Title>
                  <Dialog.Description className="dialog-description">
                    証明書の失効前に通知するタイミングを指定します。
                  </Dialog.Description>
                  <form className="dialog-form timing-dialog-form" onSubmit={saveTimingCondition}>
                    <Field label="値">
                      <input
                        type="number"
                        min="1"
                        max="17520"
                        value={timingForm.value}
                        onChange={(event) =>
                          setTimingForm({ ...timingForm, value: event.target.value })
                        }
                        placeholder="例: 7"
                        required
                      />
                    </Field>
                    <Field label="単位">
                      <select
                        value={timingForm.unit}
                        onChange={(event) =>
                          setTimingForm({ ...timingForm, unit: event.target.value })
                        }
                      >
                        <option value="hours">時間前</option>
                        <option value="days">日前</option>
                        <option value="weeks">週間前</option>
                      </select>
                    </Field>
                    <div className="dialog-actions">
                      <Dialog.Close asChild>
                        <button className="secondary" type="button">
                          キャンセル
                        </button>
                      </Dialog.Close>
                      <button className="primary" type="submit">
                        {editingConditionIndex === null ? '追加' : '更新'}
                      </button>
                    </div>
                  </form>
                </Dialog.Content>
              </Dialog.Portal>
            </Dialog.Root>
          </section>

          <section className="panel">
            <h2>通知方法</h2>
            <label className="check-row locked">
              <input type="checkbox" checked readOnly />
              アプリ内アラート
            </label>
            <label className="check-row">
              <input
                type="checkbox"
                checked={pushEnabled}
                onChange={(event) => setPushEnabled(event.target.checked)}
              />
              プッシュ通知
            </label>

            <div className="webhook-box">
              <h3>Webhook</h3>
              {availableWebhooks.length === 0 ? (
                <p className="muted">登録済みのWebhookはありません。</p>
              ) : (
                availableWebhooks.map((webhook) => (
                  <label className="check-row" key={webhook.notificationMethodId}>
                    <input
                      type="checkbox"
                      checked={webhookMethodIds.includes(webhook.notificationMethodId)}
                      onChange={() => toggleWebhook(webhook.notificationMethodId)}
                    />
                    <span>
                      <strong>{webhook.alias}</strong>
                      <small>{webhook.url}</small>
                    </span>
                  </label>
                ))
              )}
            </div>
          </section>

          <div className="settings-actions">
            <button className="primary" disabled={busy}>
              <Save aria-hidden="true" size={18} />
              保存
            </button>
            <ConfirmDialog
              title="サイト設定を削除"
              description="このサイトの通知タイミングと通知方法の設定を削除します。"
              onConfirm={deleteSettings}
              disabled={busy}
              trigger={
                <button type="button" className="secondary danger-text" disabled={busy}>
                  設定を削除
                </button>
              }
            />
          </div>
        </form>
      </section>
    </main>
  );
}
