"use client";

import { FormEvent, useCallback, useEffect, useMemo, useState } from "react";

type Platform = "instagram" | "threads";
type Brand = { id: string; name: string; description: string; color: string };
type Account = {
  id: string; brand_id: string; platform: Platform; platform_user_id: string; username: string;
  profile_image_url: string | null; token_expires_at: number | null; status: string;
};
type Target = { id: string; platform: Platform; status: string; error_message?: string | null };
type Post = {
  id: string; brand_id: string; content: string; media_url: string | null; media_type: "image" | "video" | null;
  alt_text: string | null; scheduled_for: number; timezone: string; status: string; error_message: string | null;
  targets: Target[];
};

const platformLabel: Record<Platform, string> = { instagram: "인스타그램", threads: "스레드" };
const statusLabel: Record<string, string> = {
  scheduled: "예약됨", processing: "게시 중", published: "게시됨", failed: "실패", cancelled: "취소됨",
};

async function requestJson<T>(url: string, init?: RequestInit): Promise<T> {
  const response = await fetch(url, init);
  const payload = await response.json().catch(() => ({})) as T & { error?: string };
  if (!response.ok) throw new Error(payload.error || "요청을 처리하지 못했습니다.");
  return payload;
}

function sameDate(timestamp: number, date: Date) {
  const target = new Date(timestamp);
  return target.getFullYear() === date.getFullYear() && target.getMonth() === date.getMonth() && target.getDate() === date.getDate();
}

function toDateTimeLocal(date: Date) {
  const offset = date.getTimezoneOffset();
  return new Date(date.getTime() - offset * 60000).toISOString().slice(0, 16);
}

function PlatformBadge({ platform, muted = false }: { platform: Platform; muted?: boolean }) {
  return <span className={`platform-badge ${platform} ${muted ? "muted" : ""}`}>{platform === "instagram" ? "◎" : "@"}</span>;
}

export default function Dashboard() {
  const [view, setView] = useState<"posts" | "brands">("posts");
  const [brands, setBrands] = useState<Brand[]>([]);
  const [brandId, setBrandId] = useState("");
  const [accounts, setAccounts] = useState<Account[]>([]);
  const [posts, setPosts] = useState<Post[]>([]);
  const [configured, setConfigured] = useState<Record<Platform, boolean>>({ instagram: false, threads: false });
  const [month, setMonth] = useState(() => new Date(new Date().getFullYear(), new Date().getMonth(), 1));
  const [selectedDate, setSelectedDate] = useState(() => new Date());
  const [selectedPostId, setSelectedPostId] = useState<string | null>(null);
  const [brandMenu, setBrandMenu] = useState(false);
  const [composerOpen, setComposerOpen] = useState(false);
  const [brandModalOpen, setBrandModalOpen] = useState(false);
  const [brandEditOpen, setBrandEditOpen] = useState(false);
  const [composerSchedule, setComposerSchedule] = useState("");
  const [toast, setToast] = useState<string | null>(null);
  const [busy, setBusy] = useState(false);

  const selectedBrand = brands.find((brand) => brand.id === brandId) || brands[0];
  const selectedPost = posts.find((post) => post.id === selectedPostId) || posts.find((post) => sameDate(post.scheduled_for, selectedDate)) || null;

  const loadBrands = useCallback(async () => {
    const data = await requestJson<{ brands: Brand[] }>("/api/brands");
    setBrands(data.brands);
    setBrandId((current) => current && data.brands.some((brand) => brand.id === current) ? current : data.brands[0]?.id || "");
  }, []);

  const loadBrandData = useCallback(async (currentBrandId: string) => {
    if (!currentBrandId) return;
    const [accountData, postData] = await Promise.all([
      requestJson<{ accounts: Account[]; configured: Record<Platform, boolean> }>(`/api/accounts?brandId=${encodeURIComponent(currentBrandId)}`),
      requestJson<{ posts: Post[] }>(`/api/posts?brandId=${encodeURIComponent(currentBrandId)}`),
    ]);
    setAccounts(accountData.accounts);
    setConfigured(accountData.configured);
    setPosts(postData.posts);
  }, []);

  useEffect(() => {
    // eslint-disable-next-line react-hooks/set-state-in-effect -- initial API hydration belongs to this effect
    loadBrands().catch((error) => setToast(error.message));
    const params = new URLSearchParams(window.location.search);
    if (params.get("view") === "brands") setView("brands");
    if (params.get("brandId")) setBrandId(params.get("brandId")!);
    const oauth = params.get("oauth");
    if (oauth === "connected") setToast(`${platformLabel[params.get("platform") as Platform]} 계정이 연결되었습니다.`);
    if (oauth === "missing-config") setToast(`${platformLabel[params.get("platform") as Platform]} 앱 설정이 먼저 필요합니다.`);
    if (oauth === "error") setToast(params.get("message") || "계정을 연결하지 못했습니다.");
    if (oauth) window.history.replaceState({}, "", "/");
  }, [loadBrands]);

  useEffect(() => {
    // eslint-disable-next-line react-hooks/set-state-in-effect -- reload when the selected brand changes
    loadBrandData(brandId).catch((error) => setToast(error.message));
  }, [brandId, loadBrandData]);

  useEffect(() => {
    if (!toast) return;
    const timer = window.setTimeout(() => setToast(null), 4500);
    return () => window.clearTimeout(timer);
  }, [toast]);

  const calendarDays = useMemo(() => {
    const first = new Date(month.getFullYear(), month.getMonth(), 1);
    const start = new Date(first);
    start.setDate(1 - first.getDay());
    return Array.from({ length: 42 }, (_, index) => {
      const date = new Date(start);
      date.setDate(start.getDate() + index);
      return date;
    });
  }, [month]);

  const openComposer = (date = selectedDate) => {
    const noon = new Date(date);
    noon.setHours(12, 0, 0, 0);
    setComposerSchedule(toDateTimeLocal(new Date(Math.max(noon.getTime(), Date.now() + 10 * 60000))));
    setSelectedDate(date);
    setComposerOpen(true);
  };

  const refresh = () => loadBrandData(brandId).catch((error) => setToast(error.message));

  async function createBrand(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    const form = new FormData(event.currentTarget);
    setBusy(true);
    try {
      const data = await requestJson<{ id: string }>("/api/brands", {
        method: "POST", headers: { "content-type": "application/json" },
        body: JSON.stringify({ name: form.get("name"), description: form.get("description") }),
      });
      await loadBrands();
      setBrandId(data.id);
      setBrandModalOpen(false);
      setView("brands");
      setToast("새 브랜드를 추가했습니다.");
    } catch (error) { setToast(error instanceof Error ? error.message : "브랜드를 만들지 못했습니다."); }
    finally { setBusy(false); }
  }

  async function createPost(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    const form = new FormData(event.currentTarget);
    const platforms = (["instagram", "threads"] as Platform[]).filter((platform) => form.get(platform) === "on");
    setBusy(true);
    try {
      await requestJson("/api/posts", {
        method: "POST", headers: { "content-type": "application/json" },
        body: JSON.stringify({
          brandId, content: form.get("content"), mediaUrl: form.get("mediaUrl"), mediaType: form.get("mediaType"),
          altText: form.get("altText"), scheduledFor: new Date(String(form.get("scheduledFor"))).getTime(),
          timezone: Intl.DateTimeFormat().resolvedOptions().timeZone, platforms,
        }),
      });
      setComposerOpen(false);
      await refresh();
      setToast("게시물을 예약했습니다.");
    } catch (error) { setToast(error instanceof Error ? error.message : "예약하지 못했습니다."); }
    finally { setBusy(false); }
  }

  async function updateBrand(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    if (!selectedBrand) return;
    const form = new FormData(event.currentTarget);
    setBusy(true);
    try {
      await requestJson(`/api/brands/${selectedBrand.id}`, {
        method: "PATCH", headers: { "content-type": "application/json" },
        body: JSON.stringify({ name: form.get("name"), description: form.get("description") }),
      });
      await loadBrands();
      setBrandEditOpen(false);
      setToast("브랜드 정보를 저장했습니다.");
    } catch (error) { setToast(error instanceof Error ? error.message : "저장하지 못했습니다."); }
    finally { setBusy(false); }
  }

  async function deleteBrand() {
    if (!selectedBrand || !window.confirm(`${selectedBrand.name} 브랜드와 예약 데이터를 삭제할까요?`)) return;
    setBusy(true);
    try {
      await requestJson(`/api/brands/${selectedBrand.id}`, { method: "DELETE" });
      setBrandEditOpen(false);
      await loadBrands();
      setToast("브랜드를 삭제했습니다.");
    } catch (error) { setToast(error instanceof Error ? error.message : "삭제하지 못했습니다."); }
    finally { setBusy(false); }
  }

  async function publishNow(post: Post) {
    setBusy(true);
    try {
      const result = await requestJson<{ status: string; errors: string[] }>(`/api/posts/${post.id}/publish`, { method: "POST" });
      setToast(result.errors.length ? result.errors.join(" / ") : "게시를 완료했습니다.");
      await refresh();
    } catch (error) { setToast(error instanceof Error ? error.message : "게시하지 못했습니다."); }
    finally { setBusy(false); }
  }

  async function cancelPost(post: Post) {
    if (!window.confirm("이 예약을 취소할까요?")) return;
    await requestJson(`/api/posts/${post.id}`, { method: "DELETE" }).then(refresh).catch((error) => setToast(error.message));
  }

  async function disconnect(account: Account) {
    if (!window.confirm(`${platformLabel[account.platform]} @${account.username} 연결을 해제할까요?`)) return;
    await requestJson(`/api/accounts/${account.id}`, { method: "DELETE" }).then(refresh).catch((error) => setToast(error.message));
  }

  const selectView = (next: "posts" | "brands") => {
    setView(next);
    setBrandMenu(false);
  };

  return (
    <main className="app-shell">
      <aside className="sidebar">
        <div className="wordmark">kavenix</div>
        <button className="workspace-switch" onClick={() => setBrandMenu((open) => !open)}>
          <span className="workspace-avatar">{selectedBrand?.name.slice(0, 1) || "K"}</span>
          <span className="workspace-copy"><strong>{selectedBrand?.name || "브랜드"}</strong><small>브랜드 전환</small></span>
          <span>⌃⌄</span>
        </button>
        {brandMenu && (
          <div className="sidebar-brand-menu">
            {brands.map((brand) => <button key={brand.id} onClick={() => { setBrandId(brand.id); setBrandMenu(false); }}>{brand.name}{brand.id === brandId && " ✓"}</button>)}
            <button onClick={() => { setBrandModalOpen(true); setBrandMenu(false); }}>＋ 새 브랜드</button>
          </div>
        )}
        <nav aria-label="주 메뉴">
          <button className={`nav-item ${view === "posts" ? "active" : ""}`} onClick={() => selectView("posts")}><span>▦</span><b>게시물</b></button>
          <button className={`nav-item ${view === "brands" ? "active" : ""}`} onClick={() => selectView("brands")}><span>▱</span><b>내 브랜드</b></button>
        </nav>
        <div className="nav-divider" />
        <nav className="support-nav">
          <button className="nav-item"><span>?</span><b>이용 가이드</b></button>
          <button className="nav-item"><span>◈</span><b>문의하기</b></button>
        </nav>
        <div className="sidebar-footer">
          <button><span>KS</span><b>KS Company</b><small>⌃⌄</small></button>
        </div>
      </aside>

      {view === "posts" ? (
        <section className="planner-layout">
          <div className="calendar-pane">
            <header className="calendar-header">
              <button aria-label="이전 달" onClick={() => setMonth(new Date(month.getFullYear(), month.getMonth() - 1, 1))}>‹</button>
              <strong>{month.getFullYear()}년 {month.getMonth() + 1}월</strong>
              <button aria-label="다음 달" onClick={() => setMonth(new Date(month.getFullYear(), month.getMonth() + 1, 1))}>›</button>
            </header>
            <div className="weekdays">{["일", "월", "화", "수", "목", "금", "토"].map((day) => <span key={day}>{day}</span>)}</div>
            <div className="calendar-grid">
              {calendarDays.map((date) => {
                const dayPosts = posts.filter((post) => sameDate(post.scheduled_for, date));
                const selected = sameDate(selectedDate.getTime(), date);
                return (
                  <button key={date.toISOString()} className={`day ${date.getMonth() !== month.getMonth() ? "outside" : ""} ${selected ? "selected" : ""}`}
                    onClick={() => { setSelectedDate(date); setSelectedPostId(dayPosts[0]?.id || null); }}>
                    <span className="day-number">{date.getDate()}</span>
                    <span className="day-platforms">
                      {dayPosts.flatMap((post) => post.targets).slice(0, 3).map((target) => <PlatformBadge key={target.id} platform={target.platform} muted={target.status === "cancelled"} />)}
                    </span>
                  </button>
                );
              })}
            </div>
          </div>
          <div className="schedule-pane">
            <header className="schedule-header">
              <strong>{selectedDate.getMonth() + 1}월 {selectedDate.getDate()}일</strong>
              <button onClick={() => openComposer()}>▣ 새 일정</button>
              <button aria-label="더보기">•••</button>
            </header>
            {selectedPost ? (
              <article className="post-preview">
                <div className="post-meta-row">
                  <span className={`status-dot ${selectedPost.status}`} />
                  <b>{new Date(selectedPost.scheduled_for).toLocaleTimeString("ko-KR", { hour: "numeric", minute: "2-digit" })}</b>
                  <span className={`status-pill ${selectedPost.status}`}>{statusLabel[selectedPost.status] || selectedPost.status}</span>
                  <button onClick={() => cancelPost(selectedPost)} disabled={!['scheduled','failed'].includes(selectedPost.status)}>예약 취소</button>
                </div>
                <div className="social-preview-card">
                  <div className="social-profile">
                    <span className="profile-ring">{selectedBrand?.name.slice(0, 1)}</span>
                    <div><strong>{selectedBrand?.name}</strong><small>예약 게시물</small></div><span>•••</span>
                  </div>
                  {selectedPost.media_url ? (
                    <div className="media-preview" style={{ backgroundImage: `url(${selectedPost.media_url})` }}><span>미디어 미리보기</span></div>
                  ) : (
                    <div className="text-preview"><span>@</span><p>{selectedPost.content}</p></div>
                  )}
                  <div className="preview-actions">♡ ◯ ▽ <span>⌑</span></div>
                  <p className="preview-caption"><b>{selectedBrand?.name}</b> {selectedPost.content}</p>
                </div>
                <div className="target-list">
                  {selectedPost.targets.map((target) => (
                    <div key={target.id}><PlatformBadge platform={target.platform} /><span>{platformLabel[target.platform]}</span><b>{statusLabel[target.status] || target.status}</b></div>
                  ))}
                </div>
                {selectedPost.error_message && <div className="error-box">{selectedPost.error_message}</div>}
                {['scheduled','failed'].includes(selectedPost.status) && <button className="wide-primary" disabled={busy} onClick={() => publishNow(selectedPost)}>지금 게시</button>}
              </article>
            ) : (
              <div className="empty-schedule"><span>＋</span><strong>예약된 게시물이 없습니다</strong><p>이 날짜에 Instagram 또는 Threads 게시물을 예약해보세요.</p><button onClick={() => openComposer()}>새 일정 만들기</button></div>
            )}
            <button className="floating-create" aria-label="새 일정" onClick={() => openComposer()}>＋</button>
          </div>
        </section>
      ) : (
        <section className="brand-page">
          <div className="brand-panel">
            <header className="brand-toolbar">
              <button className="brand-select" onClick={() => setBrandMenu((open) => !open)}><b>{selectedBrand?.name}</b><span>⌄</span></button>
              <button className="square-button" aria-label="브랜드 추가" onClick={() => setBrandModalOpen(true)}>＋</button>
              <button className="ghost-button" onClick={() => setBrandEditOpen(true)}>✎ 편집</button>
              <button className="dark-button" onClick={() => openComposer()}>＋ 새 게시물</button>
            </header>
            <div className="brand-fields">
              <label><span>업종</span><input value="기술" readOnly /></label>
              <div className="brand-field-split"><label><span>국가/지역</span><input value="대한민국" readOnly /></label><label><span>위치</span><input value="" placeholder="위치" readOnly /></label></div>
              <label><span>대상 청중</span><input value="" placeholder="대상 청중" readOnly /></label>
              <div className="brand-tags"><span>1인기업</span><span>1인대표</span><span>스타트업</span><span>바이브코더</span></div>
              <label className="full"><span>소개</span><textarea value={selectedBrand?.description || ""} readOnly /></label>
            </div>
            <div className="section-title"><strong>SNS 계정</strong><span>브랜드별로 Instagram과 Threads 계정을 연결하세요.</span></div>
            <div className="account-grid">
              {(["instagram", "threads"] as Platform[]).map((platform) => {
                const account = accounts.find((item) => item.platform === platform);
                return (
                  <article className="account-card" key={platform}>
                    <div className={`account-card-top ${platform}`}><PlatformBadge platform={platform} /></div>
                    {account ? (
                      <>
                        <div className="account-info"><span className="profile-ring">{account.username.slice(0, 1)}</span><div><h3>{platformLabel[platform]}</h3><p>@{account.username}</p></div><span className="connected-badge">연결됨</span></div>
                        <p className="account-note">이 브랜드의 {platformLabel[platform]} 예약 게시물이 이 계정으로 게시됩니다.</p>
                        <div className="account-actions"><a href={`/api/oauth/meta?platform=${platform}&brandId=${brandId}`}>재연결</a><button onClick={() => disconnect(account)}>연결 해제</button></div>
                      </>
                    ) : (
                      <>
                        <div className="account-info"><span className="profile-ring">{platform === "instagram" ? "IG" : "@"}</span><div><h3>{platformLabel[platform]}</h3><p>연결된 계정 없음</p></div></div>
                        <p className="account-note">{platform === "instagram" ? "비즈니스 또는 크리에이터 계정이 필요합니다." : "Threads 프로필을 연결해 텍스트 게시물을 예약할 수 있습니다."}</p>
                        <a className="connect-button" href={`/api/oauth/meta?platform=${platform}&brandId=${brandId}`}>{configured[platform] ? `${platformLabel[platform]} 연결` : "연동 설정 후 연결"}</a>
                      </>
                    )}
                  </article>
                );
              })}
            </div>
          </div>
        </section>
      )}

      {composerOpen && (
        <div className="modal-backdrop" role="presentation" onMouseDown={(event) => { if (event.currentTarget === event.target) setComposerOpen(false); }}>
          <form className="modal composer-modal" onSubmit={createPost}>
            <header><div><small>새 일정</small><h2>게시물 예약</h2></div><button type="button" onClick={() => setComposerOpen(false)}>×</button></header>
            <label><span>브랜드</span><select value={brandId} onChange={(event) => setBrandId(event.target.value)}>{brands.map((brand) => <option key={brand.id} value={brand.id}>{brand.name}</option>)}</select></label>
            <fieldset><legend>게시 플랫폼</legend>{(["instagram","threads"] as Platform[]).map((platform) => <label className="platform-choice" key={platform}><input type="checkbox" name={platform} defaultChecked /><PlatformBadge platform={platform} /><span><b>{platformLabel[platform]}</b><small>{accounts.some((account) => account.platform === platform) ? "계정 연결됨" : "연결 대기"}</small></span></label>)}</fieldset>
            <label><span>게시글</span><textarea name="content" required maxLength={2200} rows={6} placeholder="게시할 내용을 입력하세요." /></label>
            <div className="form-row"><label><span>미디어 URL</span><input type="url" name="mediaUrl" placeholder="https://.../image.jpg" /></label><label><span>유형</span><select name="mediaType"><option value="image">이미지</option><option value="video">영상</option></select></label></div>
            <label><span>대체 텍스트</span><input name="altText" placeholder="이미지 또는 영상 설명" /></label>
            <label><span>예약 일시</span><input type="datetime-local" name="scheduledFor" required defaultValue={composerSchedule} /></label>
            <p className="form-help">Instagram 게시에는 Meta가 접근할 수 있는 공개 이미지 또는 영상 URL이 필요합니다. Threads는 텍스트만으로도 게시할 수 있습니다.</p>
            <footer><button type="button" onClick={() => setComposerOpen(false)}>취소</button><button className="dark-button" disabled={busy}>예약하기</button></footer>
          </form>
        </div>
      )}

      {brandModalOpen && (
        <div className="modal-backdrop" role="presentation" onMouseDown={(event) => { if (event.currentTarget === event.target) setBrandModalOpen(false); }}>
          <form className="modal brand-modal" onSubmit={createBrand}>
            <header><div><small>내 브랜드</small><h2>새 브랜드 추가</h2></div><button type="button" onClick={() => setBrandModalOpen(false)}>×</button></header>
            <label><span>브랜드 이름</span><input name="name" maxLength={60} required placeholder="예: 오피셜메일" /></label>
            <label><span>브랜드 소개</span><textarea name="description" rows={4} maxLength={500} placeholder="브랜드를 간단히 소개해주세요." /></label>
            <footer><button type="button" onClick={() => setBrandModalOpen(false)}>취소</button><button className="dark-button" disabled={busy}>브랜드 추가</button></footer>
          </form>
        </div>
      )}

      {brandEditOpen && selectedBrand && (
        <div className="modal-backdrop" role="presentation" onMouseDown={(event) => { if (event.currentTarget === event.target) setBrandEditOpen(false); }}>
          <form className="modal brand-modal" onSubmit={updateBrand}>
            <header><div><small>내 브랜드</small><h2>브랜드 편집</h2></div><button type="button" onClick={() => setBrandEditOpen(false)}>×</button></header>
            <label><span>브랜드 이름</span><input name="name" maxLength={60} required defaultValue={selectedBrand.name} /></label>
            <label><span>브랜드 소개</span><textarea name="description" rows={4} maxLength={500} defaultValue={selectedBrand.description} /></label>
            <div className="danger-zone"><button type="button" onClick={deleteBrand} disabled={busy}>브랜드 삭제</button><span>최소 한 개의 브랜드는 유지됩니다.</span></div>
            <footer><button type="button" onClick={() => setBrandEditOpen(false)}>취소</button><button className="dark-button" disabled={busy}>저장</button></footer>
          </form>
        </div>
      )}

      {toast && <div className="toast" role="status">{toast}</div>}
    </main>
  );
}
