import { useEffect, useState, ReactNode } from "react";
import { Link } from "react-router-dom";
import { AppConfig, apiGet, apiPost } from "../api";
import { useToast } from "../lib/toast";
import { PageHead, StatCard, Loading, Empty, Avatar, timeAgo, fmtNumber, formatNZ } from "../components/ui";
import {
  IconAndroid,
  IconApple,
  IconCalendar,
  IconChevron,
  IconDisc,
  IconEmby,
  IconGrid,
  IconHeart,
  IconHome,
  IconImage,
  IconLayers,
  IconMusic,
  IconPlay,
  IconRefresh,
  IconUser,
  IconWand,
  IconWeb,
} from "../components/icons";

interface Props {
  config: AppConfig | null;
  navidromeConnected: boolean;
}

interface DashboardData {
  emby: {
    connected: boolean;
    url: string;
    movies: number;
    series: number;
    episodes: number;
    collections: number;
    users: number;
    favorites_collections: number;
    last_added: string | null;
  };
  navidrome: {
    connected: boolean;
    configured?: boolean;
    artist_count?: number;
    album_count?: number;
    song_count?: number;
    genre_count?: number;
    top_genres?: { name: string; song_count: number; album_count: number }[];
  };
  music: { available: boolean; root: string };
}

interface UserActivity {
  id: string;
  name: string;
  last_login: string | null;
  last_activity: string | null;
  ip: string | null;
  device: string | null;
  client: string | null;
}

interface ActivitySummary {
  user_count: number;
  device_count: number;
  platforms: { android: number; ios: number; web: number; other: number };
  platform_pct: { android: number; ios: number; web: number; other: number };
}

interface FormatData {
  total: number;
  formats: { format: string; count: number }[];
}

const FORMATS_SESSION_KEY = "dashboard.navidrome.formats";

function readCachedFormats(): FormatData | null {
  try {
    const raw = window.sessionStorage.getItem(FORMATS_SESSION_KEY);
    if (!raw) return null;
    const parsed = JSON.parse(raw);
    if (!parsed || typeof parsed !== "object" || !Array.isArray(parsed.formats) || typeof parsed.total !== "number") return null;
    return parsed as FormatData;
  } catch {
    return null;
  }
}

function writeCachedFormats(data: FormatData | null) {
  try {
    if (!data) {
      window.sessionStorage.removeItem(FORMATS_SESSION_KEY);
      return;
    }
    window.sessionStorage.setItem(FORMATS_SESSION_KEY, JSON.stringify(data));
  } catch {
    // Ignore browser storage failures; the in-memory state still works.
  }
}

const FORMAT_COLORS: Record<string, string> = {
  flac: "var(--accent)",
  mp3: "var(--amber)",
  m4a: "var(--green)",
  aac: "var(--green)",
  alac: "#7fd1ff",
  ogg: "var(--purple)",
  opus: "var(--purple)",
  wav: "#8fa3b8",
  wma: "#c98cf3",
  other: "var(--text-3)",
};
const formatColor = (fmt: string) => FORMAT_COLORS[fmt.toLowerCase()] || "#6b7c90";

const tools = [
  { to: "/emby/generator", label: "Thumb Studio", icon: <IconImage />, cat: "Emby" },
  { to: "/emby/avatar-generator", label: "Avatars", icon: <IconUser />, cat: "Emby" },
  { to: "/emby/collections", label: "Collection Covers", icon: <IconLayers />, cat: "Emby" },
  { to: "/emby/airing", label: "Airing Calendar", icon: <IconCalendar />, cat: "Emby" },
  { to: "/emby/bulk-assign", label: "Batch Artwork", icon: <IconGrid />, cat: "Emby" },
  { to: "/emby/favorites", label: "Favorites", icon: <IconHeart />, cat: "Emby" },
  { to: "/emby/homescreen", label: "Home Screen", icon: <IconLayers />, cat: "Emby" },
  { to: "/navidrome/library", label: "Music Library", icon: <IconDisc />, cat: "Navidrome" },
  { to: "/navidrome/reporting", label: "Reporting", icon: <IconMusic />, cat: "Navidrome" },
  { to: "/navidrome/cleanup", label: "Library Cleanup", icon: <IconWand />, cat: "Navidrome" },
];

function MiniStat({ icon, value, label }: { icon: ReactNode; value: ReactNode; label: string }) {
  return (
    <div className="mini-stat">
      <div className="stat-icon">{icon}</div>
      <div className="stat-meta">
        <div className="stat-value">{value}</div>
        <div className="stat-label">{label}</div>
      </div>
    </div>
  );
}

function StatusBadge({ configured, connected }: { configured: boolean; connected: boolean }) {
  if (!configured) return <span className="badge">not configured</span>;
  return <span className={`badge ${connected ? "badge-ok" : "badge-bad"}`}>{connected ? "connected" : "offline"}</span>;
}

type DevicePlatform = "apple" | "android" | "web" | "other";

function detectPlatform(user: UserActivity): DevicePlatform {
  const haystack = [user.device, user.client].filter(Boolean).join(" ").toLowerCase();
  if (/(iphone|ipad|ipod|apple tv|appletv|ios|tvos|mac|macos|safari)/.test(haystack)) return "apple";
  if (/(android|google tv|shield|fire tv|firetv|chromecast)/.test(haystack)) return "android";
  if (/(web|chrome|firefox|edge|browser|opera)/.test(haystack)) return "web";
  return "other";
}

function platformLabel(platform: DevicePlatform) {
  if (platform === "apple") return "Apple";
  if (platform === "android") return "Android";
  if (platform === "web") return "Web";
  return "Other";
}

function platformIcon(platform: DevicePlatform) {
  if (platform === "apple") return <IconApple />;
  if (platform === "android") return <IconAndroid />;
  if (platform === "web") return <IconWeb />;
  return <IconUser />;
}

function platformBadgeClass(platform: DevicePlatform) {
  if (platform === "apple") return "activity-device-chip apple";
  if (platform === "android") return "activity-device-chip android";
  if (platform === "web") return "activity-device-chip web";
  return "activity-device-chip";
}

function platformSummaryItems(summary: ActivitySummary) {
  return [
    { key: "apple", label: "Apple", count: summary.platforms.ios, pct: summary.platform_pct.ios, icon: <IconApple /> },
    { key: "android", label: "Android", count: summary.platforms.android, pct: summary.platform_pct.android, icon: <IconAndroid /> },
    { key: "web", label: "Web", count: summary.platforms.web, pct: summary.platform_pct.web, icon: <IconWeb /> },
    { key: "other", label: "Other", count: summary.platforms.other, pct: summary.platform_pct.other, icon: <IconUser /> },
  ].filter((item) => item.count > 0);
}

export default function Dashboard({ config, navidromeConnected }: Props) {
  const toast = useToast();
  const [data, setData] = useState<DashboardData | null>(null);
  const [activity, setActivity] = useState<UserActivity[] | null>(null);
  const [activitySummary, setActivitySummary] = useState<ActivitySummary | null>(null);
  const [formats, setFormats] = useState<FormatData | null>(() => readCachedFormats());
  const [formatsLoading, setFormatsLoading] = useState(false);
  const [loading, setLoading] = useState(true);
  const [embyScanning, setEmbyScanning] = useState(false);
  const [navScanning, setNavScanning] = useState(false);

  async function refreshEmby() {
    setEmbyScanning(true);
    try {
      await apiPost("/api/emby/refresh-libraries");
      toast("Emby library scan started", "ok");
    } catch (err: any) {
      toast(err.message, "err");
    } finally {
      setEmbyScanning(false);
    }
  }

  async function scanNavidrome() {
    setNavScanning(true);
    try {
      await apiPost("/api/navidrome/scan");
      toast("Navidrome scan started", "ok");
    } catch (err: any) {
      toast(err.message, "err");
    } finally {
      setNavScanning(false);
    }
  }

  // Format breakdown pages the whole song list, so it's cached server-side for the
  // session. A normal page load reuses that cache; pass force to rescan on demand.
  function loadFormats(force = false) {
    if (!force) {
      const cached = readCachedFormats();
      if (cached) {
        setFormats(cached);
        setFormatsLoading(false);
        return;
      }
    }
    setFormatsLoading(true);
    apiGet<FormatData>(`/api/navidrome/formats${force ? "?refresh=true" : ""}`)
      .then((result) => {
        setFormats(result);
        writeCachedFormats(result);
      })
      .catch(() => setFormats((current) => current ?? null))
      .finally(() => setFormatsLoading(false));
  }

  function load(force = false) {
    setLoading(true);
    apiGet<DashboardData>("/api/dashboard")
      .then(setData)
      .catch(() => setData(null))
      .finally(() => setLoading(false));
    apiGet<{ users: UserActivity[]; summary: ActivitySummary }>("/api/emby/user-activity")
      .then((d) => {
        setActivity(d.users);
        setActivitySummary(d.summary);
      })
      .catch(() => {
        setActivity([]);
        setActivitySummary(null);
      });
    loadFormats(force);
  }
  useEffect(() => {
    load();
  }, []);

  const e = data?.emby;
  const n = data?.navidrome;
  const genres = n?.top_genres ?? [];
  const maxGenre = genres.reduce((m, g) => Math.max(m, g.song_count), 0) || 1;

  return (
    <>
      <div className="row between" style={{ alignItems: "flex-start" }}>
        <PageHead title="Dashboard" icon={<IconHome />} />
        <button className="btn btn-sm" onClick={() => load()} disabled={loading || formatsLoading}>
          {loading ? <span className="spinner" /> : <IconRefresh />} Refresh
        </button>
      </div>

      {loading && !data ? (
        <Loading label="Gathering library stats…" />
      ) : (
        <>
          <div className="dash-split">
            {/* ── Emby column ── */}
            <div className="panel">
              <div className="panel-head">
                <div className="stat-icon" style={{ width: 30, height: 30, borderRadius: 8 }}>
                  <IconEmby />
                </div>
                <h3 className="grow">Emby</h3>
                <StatusBadge configured={!!e?.connected} connected={!!e?.connected} />
                <button className="btn btn-sm" onClick={refreshEmby} disabled={embyScanning || !e?.connected}>
                  {embyScanning ? <span className="spinner" /> : <IconRefresh />} Scan libraries
                </button>
              </div>
              <div className="panel-body col" style={{ gap: 14 }}>
                <div className="mini-grid">
                  <MiniStat icon={<IconPlay />} value={fmtNumber(e?.movies)} label="Movies" />
                  <MiniStat icon={<IconGrid />} value={fmtNumber(e?.series)} label="Series" />
                  <MiniStat icon={<IconLayers />} value={fmtNumber(e?.episodes)} label="Episodes" />
                  <MiniStat icon={<IconLayers />} value={fmtNumber(e?.collections)} label="Collections" />
                  <MiniStat icon={<IconUser />} value={fmtNumber(e?.users)} label="Users" />
                  <MiniStat icon={<IconHeart />} value={fmtNumber(e?.favorites_collections)} label="Favorites" />
                </div>
                <div className="mini-stat">
                  <div className="stat-icon">
                    <IconCalendar />
                  </div>
                  <div className="stat-meta">
                    <div className="stat-value" style={{ fontSize: 17 }}>
                      {timeAgo(e?.last_added)}
                    </div>
                    <div className="stat-label">Last item added · {e?.url}</div>
                  </div>
                </div>
              </div>
            </div>

            {/* ── Navidrome column ── */}
            <div className="panel">
              <div className="panel-head">
                <div className="stat-icon" style={{ width: 30, height: 30, borderRadius: 8 }}>
                  <IconMusic />
                </div>
                <h3 className="grow">Navidrome</h3>
                <StatusBadge configured={!!n?.configured} connected={!!n?.connected} />
                <button className="btn btn-sm" onClick={scanNavidrome} disabled={navScanning || !n?.connected}>
                  {navScanning ? <span className="spinner" /> : <IconRefresh />} Scan library
                </button>
              </div>
              <div className="panel-body col" style={{ gap: 14 }}>
                {!n?.connected ? (
                  <Empty icon={<IconMusic />}>
                    {n?.configured
                      ? "Navidrome is configured but offline."
                      : "Navidrome is not configured. Add your server details in Settings."}
                  </Empty>
                ) : (
                  <>
                    <div className="mini-grid">
                      <MiniStat icon={<IconUser />} value={fmtNumber(n?.artist_count)} label="Artists" />
                      <MiniStat icon={<IconDisc />} value={fmtNumber(n?.album_count)} label="Albums" />
                      <MiniStat icon={<IconMusic />} value={fmtNumber(n?.song_count)} label="Tracks" />
                      <MiniStat icon={<IconLayers />} value={fmtNumber(n?.genre_count)} label="Genres" />
                    </div>
                    <div>
                      <div className="row between" style={{ margin: "4px 0 8px", alignItems: "center" }}>
                        <span className="section-label" style={{ margin: 0 }}>
                          Audio formats
                        </span>
                        <button
                          className="btn btn-sm"
                          onClick={() => loadFormats(true)}
                          disabled={formatsLoading || !n?.connected}
                          title="Rescan track formats (otherwise cached for the session)"
                        >
                          {formatsLoading ? <span className="spinner" /> : <IconRefresh />}
                        </button>
                      </div>
                      {formatsLoading && !formats ? (
                        <p className="hint row gap-sm">
                          <span className="spinner" /> Analyzing track formats…
                        </p>
                      ) : !formats || formats.total === 0 ? (
                        <p className="hint">No format data.</p>
                      ) : (
                        <>
                          <div className="stack-bar">
                            {formats.formats.map((f) => (
                              <span
                                key={f.format}
                                className="stack-seg"
                                title={`${f.format}: ${f.count}`}
                                style={{ width: `${(f.count / formats.total) * 100}%`, background: formatColor(f.format) }}
                              />
                            ))}
                          </div>
                          <div className="legend">
                            {formats.formats.map((f) => (
                              <div className="legend-row" key={f.format}>
                                <span className="legend-dot" style={{ background: formatColor(f.format) }} />
                                <span className="legend-name">{f.format}</span>
                                <span className="legend-count">
                                  {fmtNumber(f.count)} · {Math.round((f.count / formats.total) * 100)}%
                                </span>
                              </div>
                            ))}
                          </div>
                        </>
                      )}
                    </div>

                    <div>
                      <div className="section-label" style={{ margin: "4px 0 8px" }}>
                        Top genres
                      </div>
                      {genres.length === 0 ? (
                        <p className="hint">No genre data.</p>
                      ) : (
                        genres.map((g) => (
                          <div className="genre-row" key={g.name}>
                            <span className="genre-name">{g.name}</span>
                            <span className="genre-bar">
                              <span className="genre-bar-fill" style={{ width: `${(g.song_count / maxGenre) * 100}%` }} />
                            </span>
                            <span className="genre-count">{fmtNumber(g.song_count)}</span>
                          </div>
                        ))
                      )}
                    </div>
                  </>
                )}
              </div>
            </div>
          </div>

          {/* ── User activity (full width) ── */}
          <div className="panel" style={{ marginBottom: 26 }}>
            <div className="panel-head">
              <IconUser className="dim" />
              <h3 className="grow">User Activity</h3>
            </div>
            {!activity ? (
              <div className="panel-body">
                <Loading />
              </div>
            ) : activity.length === 0 ? (
              <Empty icon={<IconUser />}>No Emby users found.</Empty>
            ) : (
              <div className="panel-body activity-shell">
                {activitySummary && (
                  <div className="activity-summary-grid">
                    <div className="activity-summary-card">
                      <span className="activity-summary-label">Active users</span>
                      <strong>{fmtNumber(activitySummary.user_count)}</strong>
                      <span className="activity-summary-sub">Recently seen across Emby</span>
                    </div>
                    <div className="activity-summary-card">
                      <span className="activity-summary-label">Devices</span>
                      <strong>{fmtNumber(activitySummary.device_count)}</strong>
                      <span className="activity-summary-sub">Distinct clients reported</span>
                    </div>
                    {platformSummaryItems(activitySummary).map((item) => (
                      <div className="activity-summary-card activity-summary-platform" key={item.key}>
                        <span className={`activity-summary-icon ${item.key}`}>{item.icon}</span>
                        <div>
                          <span className="activity-summary-label">{item.label}</span>
                          <strong>{item.pct}%</strong>
                        </div>
                        <span className="activity-summary-sub">{fmtNumber(item.count)} devices</span>
                      </div>
                    ))}
                  </div>
                )}

                <div className="activity-card-grid">
                  {activity.map((u) => {
                    const when = u.last_activity || u.last_login;
                    const platform = detectPlatform(u);
                    const deviceLabel = [u.device, u.client].filter(Boolean).join(" · ") || "Unknown device";
                    return (
                      <article className="activity-card" key={u.id}>
                        <div className="activity-card-head">
                          <div className="row gap-sm">
                            <Avatar name={u.name} />
                            <div className="activity-user-meta">
                              <div className="activity-user-name">{u.name}</div>
                              <div className="activity-user-when">{when ? timeAgo(when) : "Never active"}</div>
                            </div>
                          </div>
                          <span className={platformBadgeClass(platform)}>
                            {platformIcon(platform)}
                            {platformLabel(platform)}
                          </span>
                        </div>

                        <div className="activity-device-title">{deviceLabel}</div>

                        <div className="activity-card-meta">
                          <div className="activity-meta-block">
                            <span className="activity-meta-label">Last login</span>
                            <span className="activity-meta-value mono">{formatNZ(u.last_login)}</span>
                          </div>
                          <div className="activity-meta-block">
                            <span className="activity-meta-label">IP address</span>
                            <span className="activity-meta-value mono">{u.ip || "—"}</span>
                          </div>
                        </div>
                      </article>
                    );
                  })}
                </div>
              </div>
            )}
          </div>

          {/* ── Quick actions ── */}
          <div className="section-label">Tools</div>
          <div className="card-grid" style={{ gridTemplateColumns: "repeat(auto-fill, minmax(230px, 1fr))" }}>
            {tools.map((t) => (
              <Link key={t.to} to={t.to} className="panel tool-card">
                <div className="stat-icon" style={{ width: 32, height: 32 }}>
                  {t.icon}
                </div>
                <div className="grow">
                  <div className="media-title">{t.label}</div>
                  <div className="dim" style={{ fontSize: 11 }}>
                    {t.cat}
                  </div>
                </div>
                <IconChevron className="dim" />
              </Link>
            ))}
          </div>
        </>
      )}
    </>
  );
}
