"use client";

import { useEffect, useMemo, useRef, useState } from "react";

type PeriodType = "week" | "month";

type PeriodOption = {
  start: string;
  label: string;
};

type TrafficPoint = {
  date: string;
  views: number;
  visitors: number;
};

type TopPage = {
  page: string;
  views: number;
};

type BreakdownItem = {
  device?: string;
  browser?: string;
  count: number;
};

type AnalyticsData = {
  selectedPeriod: {
    type: PeriodType;
    start: string;
    label: string;
  };

  periodAnalytics: {
    visitors: number;
    pageViews: number;
    sessions: number;
    returningVisitors: number;
  };

  totalVisitors: number;
  totalPageViews: number;
  totalSessions: number;

  visitors: number;
  pageViews: number;
  sessions: number;
  returningVisitors: number;

  topPages: TopPage[];

  trafficOverTime: TrafficPoint[];

  devices: BreakdownItem[];

  browsers: BreakdownItem[];

  availableWeeks: PeriodOption[];

  availableMonths: PeriodOption[];
};

type ApiResponse = {
  success: boolean;
  data: AnalyticsData;
};

const formatNumber = (value: number) =>
  new Intl.NumberFormat("en-IN").format(
    value
  );

const formatDate = (date: string) => {
  const parsed = new Date(
    `${date}T00:00:00`
  );

  return parsed.toLocaleDateString(
    "en-IN",
    {
      day: "2-digit",
      month: "short",
    }
  );
};

const getPageName = (page: string) => {
  if (page === "/") {
    return "Homepage";
  }

  return page
    .replace(/^\/+/, "")
    .replace(/\/+/g, " / ")
    .replace(/-/g, " ")
    .replace(/\b\w/g, (letter) =>
      letter.toUpperCase()
    );
};

function StatCard({
  label,
  value,
  description,
}: {
  label: string;
  value: number;
  description: string;
}) {
  return (
    <div className="rounded-2xl border border-gray-200 bg-white p-5 shadow-sm transition-shadow hover:shadow-md">
      <p className="text-sm font-medium text-gray-500">
        {label}
      </p>

      <p className="mt-2 text-3xl font-semibold tracking-tight text-gray-900">
        {formatNumber(value)}
      </p>

      <p className="mt-1 text-xs text-gray-400">
        {description}
      </p>
    </div>
  );
}

function SectionCard({
  title,
  description,
  children,
}: {
  title: string;
  description?: string;
  children: React.ReactNode;
}) {
  return (
    <section className="rounded-2xl border border-gray-200 bg-white p-5 shadow-sm sm:p-6">
      <div className="mb-5">
        <h2 className="text-lg font-semibold text-gray-900">
          {title}
        </h2>

        {description && (
          <p className="mt-1 text-sm text-gray-500">
            {description}
          </p>
        )}
      </div>

      {children}
    </section>
  );
}

function EmptyState({
  message = "No data available for this period.",
}: {
  message?: string;
}) {
  return (
    <div className="flex min-h-45 items-center justify-center rounded-xl border border-dashed border-gray-200 bg-gray-50 px-5 text-center">
      <p className="text-sm text-gray-400">
        {message}
      </p>
    </div>
  );
}

function TrafficChart({
  data,
}: {
  data: TrafficPoint[];
}) {
  const maxValue = Math.max(
    ...data.map((item) => item.views),
    1
  );

  if (!data.length) {
    return <EmptyState />;
  }

  return (
    <div className="w-full">
      <div className="flex h-65 gap-3">
        {/* Y-axis */}
        <div className="flex w-10 flex-col justify-between pb-7 text-right text-[11px] text-gray-400">
          <span>
            {formatNumber(maxValue)}
          </span>

          <span>
            {formatNumber(
              Math.round(maxValue * 0.75)
            )}
          </span>

          <span>
            {formatNumber(
              Math.round(maxValue * 0.5)
            )}
          </span>

          <span>
            {formatNumber(
              Math.round(maxValue * 0.25)
            )}
          </span>

          <span>0</span>
        </div>

        {/* Chart */}
        <div className="relative flex min-w-0 flex-1 items-end gap-1 border-b border-l border-gray-200 px-2 pb-7 pt-3">
          {/* Grid */}
          <div className="pointer-events-none absolute inset-x-0 top-3 bottom-7 flex flex-col justify-between">
            {[0, 1, 2, 3, 4].map(
              (line) => (
                <div
                  key={line}
                  className="border-t border-dashed border-gray-100"
                />
              )
            )}
          </div>

          {data.map((item) => {
            const height =
              item.views === 0
                ? 2
                : Math.max(
                    5,
                    (item.views / maxValue) *
                      100
                  );

            return (
              <div
                key={item.date}
                className="group relative z-10 flex h-full min-w-0 flex-1 items-end"
              >
                <div className="relative flex h-full w-full items-end justify-center">
                  <div
                    className="w-full max-w-8 rounded-t-md bg-gray-900 transition-all duration-200 group-hover:bg-gray-700"
                    style={{
                      height: `${height}%`,
                    }}
                    title={`${formatDate(
                      item.date
                    )}: ${
                      item.views
                    } page views`}
                  />
                </div>

                <span className="absolute -bottom-6 left-1/2 -translate-x-1/2 whitespace-nowrap text-[10px] text-gray-400">
                  {formatDate(item.date)}
                </span>
              </div>
            );
          })}
        </div>
      </div>

      {/* Legend */}
      <div className="mt-5 flex flex-wrap items-center gap-5 text-xs text-gray-500">
        <div className="flex items-center gap-2">
          <span className="h-2.5 w-2.5 rounded-sm bg-gray-900" />
          <span>Page views</span>
        </div>

        <div>
          Unique visitors:{" "}
          <span className="font-medium text-gray-700">
            {formatNumber(
              data.reduce(
                (total, item) =>
                  total + item.visitors,
                0
              )
            )}
          </span>
        </div>
      </div>
    </div>
  );
}

function BreakdownList({
  items,
  labelKey,
}: {
  items: BreakdownItem[];
  labelKey: "device" | "browser";
}) {
  if (!items.length) {
    return <EmptyState />;
  }

  const total = items.reduce(
    (sum, item) =>
      sum + item.count,
    0
  );

  return (
    <div className="space-y-4">
      {items.map((item) => {
        const label =
          item[labelKey] || "Unknown";

        const percentage =
          total > 0
            ? (item.count / total) *
              100
            : 0;

        return (
          <div key={label}>
            <div className="mb-1.5 flex items-center justify-between gap-3 text-sm">
              <span className="truncate font-medium text-gray-700">
                {label}
              </span>

              <span className="shrink-0 text-gray-500">
                {formatNumber(
                  item.count
                )}{" "}
                <span className="text-xs text-gray-400">
                  ({percentage.toFixed(
                    0
                  )}
                  %)
                </span>
              </span>
            </div>

            <div className="h-2 overflow-hidden rounded-full bg-gray-100">
              <div
                className="h-full rounded-full bg-gray-900 transition-all duration-500"
                style={{
                  width: `${percentage}%`,
                }}
              />
            </div>
          </div>
        );
      })}
    </div>
  );
}

export default function WebsiteTrafficAnalytics() {
  const [rangeType, setRangeType] =
    useState<PeriodType>("week");

  const [
    selectedPeriodStart,
    setSelectedPeriodStart,
  ] = useState("");

  const [data, setData] =
    useState<AnalyticsData | null>(
      null
    );

  const [loading, setLoading] =
    useState(true);

  const [error, setError] =
    useState("");

  const abortControllerRef =
    useRef<AbortController | null>(
      null
    );

  /*
   * Cancel the previous request before
   * starting another one.
   */
  const fetchAnalytics = async (
    period: PeriodType,
    periodStart?: string
  ) => {
    const apiUrl =
      process.env
        .NEXT_PUBLIC_BACKEND_URL;

    if (!apiUrl) {
      setError(
        "Backend URL is not configured."
      );

      setLoading(false);

      return null;
    }

    abortControllerRef.current?.abort();

    const controller =
      new AbortController();

    abortControllerRef.current =
      controller;

    try {
      setLoading(true);
      setError("");

      const params =
        new URLSearchParams();

      params.set(
        "period",
        period
      );

      if (periodStart) {
        params.set(
          "periodStart",
          periodStart
        );
      }

      const response = await fetch(
        `${apiUrl}/api/admin/website-traffic?${params.toString()}`,
        {
          method: "GET",
          headers: {
            Authorization: `Bearer ${localStorage.getItem(
              "token"
            )}`,
          },
          cache: "no-store",
          signal:
            controller.signal,
        }
      );

      if (!response.ok) {
        if (
          response.status === 401
        ) {
          throw new Error(
            "Your admin session has expired. Please log in again."
          );
        }

        throw new Error(
          "Failed to load analytics."
        );
      }

      const result =
        (await response.json()) as ApiResponse;

      if (
        !result.success ||
        !result.data
      ) {
        throw new Error(
          "Invalid analytics response."
        );
      }

      /*
       * Ignore results from an aborted
       * request.
       */
      if (controller.signal.aborted) {
        return null;
      }

      setData(result.data);

      return result.data;
    } catch (requestError) {
      if (
        requestError instanceof
          DOMException &&
        requestError.name ===
          "AbortError"
      ) {
        return null;
      }

      if (
        requestError instanceof
        Error
      ) {
        setError(
          requestError.message
        );
      } else {
        setError(
          "Unable to load analytics."
        );
      }

      return null;
    } finally {
      if (
        !controller.signal.aborted
      ) {
        setLoading(false);
      }
    }
  };

  /*
   * Initial load and period-type change.
   *
   * IMPORTANT:
   * We intentionally do not put
   * selectedPeriodStart in this effect.
   *
   * Selecting a historical period is handled
   * directly by handlePeriodChange().
   */
  useEffect(() => {
    setSelectedPeriodStart("");

    void fetchAnalytics(
      rangeType
    );

    return () => {
      abortControllerRef.current?.abort();
    };
  }, [rangeType]);

  const periodOptions = useMemo(
    () =>
      rangeType === "week"
        ? data?.availableWeeks ?? []
        : data?.availableMonths ?? [],
    [data, rangeType]
  );

  /*
   * When current-period data arrives,
   * synchronize the selected dropdown value.
   */
  useEffect(() => {
    if (
      data?.selectedPeriod
        ?.start
    ) {
      setSelectedPeriodStart(
        data.selectedPeriod.start
      );
    }
  }, [
    data?.selectedPeriod?.start,
  ]);

  const handlePeriodChange = async (
    value: string
  ) => {
    setSelectedPeriodStart(
      value
    );

    await fetchAnalytics(
      rangeType,
      value
    );
  };

  const periodAnalytics =
    data?.periodAnalytics;

  const hasTraffic =
    Boolean(
      periodAnalytics &&
        (periodAnalytics.visitors > 0 ||
          periodAnalytics.pageViews >
            0 ||
          periodAnalytics.sessions >
            0)
    );

  const pageViews =
    periodAnalytics?.pageViews ??
    0;

  const visitors =
    periodAnalytics?.visitors ??
    0;

  const sessions =
    periodAnalytics?.sessions ??
    0;

  return (
    <div className="space-y-6">
      {/* -------------------------------- */}
      {/* PERIOD FILTER */}
      {/* -------------------------------- */}

      <section className="rounded-2xl border border-gray-200 bg-white p-5 shadow-sm sm:p-6">
        <div className="flex flex-col gap-5 lg:flex-row lg:items-end lg:justify-between">
          <div>
            <p className="text-xs font-semibold uppercase tracking-[0.18em] text-gray-400">
              Traffic period
            </p>

            <h2 className="mt-2 text-xl font-semibold text-gray-900">
              {data?.selectedPeriod
                ?.label ??
                "Website traffic"}
            </h2>

            <p className="mt-1 max-w-xl text-sm text-gray-500">
              View website traffic for
              a specific week or month.
            </p>
          </div>

          <div className="flex w-full flex-col gap-3 sm:w-auto sm:flex-row">
            <div className="flex rounded-xl border border-gray-200 bg-gray-50 p-1">
              <button
                type="button"
                onClick={() =>
                  setRangeType(
                    "week"
                  )
                }
                className={`rounded-lg px-5 py-2 text-sm font-medium transition ${
                  rangeType ===
                  "week"
                    ? "bg-white text-gray-900 shadow-sm"
                    : "text-gray-500 hover:text-gray-900"
                }`}
              >
                Week
              </button>

              <button
                type="button"
                onClick={() =>
                  setRangeType(
                    "month"
                  )
                }
                className={`rounded-lg px-5 py-2 text-sm font-medium transition ${
                  rangeType ===
                  "month"
                    ? "bg-white text-gray-900 shadow-sm"
                    : "text-gray-500 hover:text-gray-900"
                }`}
              >
                Month
              </button>
            </div>

            <select
              value={
                selectedPeriodStart
              }
              onChange={(event) =>
                void handlePeriodChange(
                  event.target.value
                )
              }
              disabled={
                loading ||
                periodOptions.length ===
                  0
              }
              className="min-w-0 rounded-xl border border-gray-200 bg-white px-4 py-2.5 text-sm font-medium text-gray-700 outline-none transition focus:ring-2 focus:ring-gray-100 disabled:cursor-not-allowed sm:min-w-57"
            >
              {periodOptions.length ===
              0 ? (
                <option value="">
                  No traffic periods
                </option>
              ) : (
                periodOptions.map(
                  (option) => (
                    <option
                      key={
                        option.start
                      }
                      value={
                        option.start
                      }
                    >
                      {option.label}
                    </option>
                  )
                )
              )}
            </select>
          </div>
        </div>
      </section>

      {/* -------------------------------- */}
      {/* ERROR */}
      {/* -------------------------------- */}

      {error && (
        <div className="rounded-2xl border border-red-200 bg-red-50 px-5 py-4 text-sm text-red-700">
          {error}
        </div>
      )}

      {/* -------------------------------- */}
      {/* LOADING */}
      {/* -------------------------------- */}

      {loading && !data ? (
        <div className="space-y-6">
          <div className="grid grid-cols-1 gap-4 sm:grid-cols-2 xl:grid-cols-4">
            {[1, 2, 3, 4].map(
              (item) => (
                <div
                  key={item}
                  className="h-32 animate-pulse rounded-2xl bg-gray-100"
                />
              )
            )}
          </div>

          <div className="h-96 animate-pulse rounded-2xl bg-gray-100" />
        </div>
      ) : (
        <>
          {/* -------------------------------- */}
          {/* OVERVIEW */}
          {/* -------------------------------- */}

          <div className="grid grid-cols-1 gap-4 sm:grid-cols-2 xl:grid-cols-4">
            <StatCard
              label="Visitors"
              value={visitors}
              description="Unique visitors in selected period"
            />

            <StatCard
              label="Page Views"
              value={pageViews}
              description="Page views in selected period"
            />

            <StatCard
              label="Sessions"
              value={sessions}
              description="Unique sessions in selected period"
            />

            <StatCard
              label="Returning Visitors"
              value={
                periodAnalytics
                  ?.returningVisitors ??
                0
              }
              description="Visitors with multiple sessions"
            />
          </div>

          {/* -------------------------------- */}
          {/* TRAFFIC */}
          {/* -------------------------------- */}

          <SectionCard
            title="Traffic Over Time"
            description={
              data?.selectedPeriod
                ?.label
                ? `Page views during ${data.selectedPeriod.label}.`
                : "Page views over time."
            }
          >
            {!hasTraffic ? (
              <EmptyState message="No traffic data available for this period." />
            ) : (
              <TrafficChart
                data={
                  data?.trafficOverTime ??
                  []
                }
              />
            )}
          </SectionCard>

          {/* -------------------------------- */}
          {/* MOST VISITED PAGES */}
          {/* -------------------------------- */}

          <SectionCard
            title="Most Visited Pages"
            description="Pages receiving the most page views in the selected period."
          >
            {data?.topPages
              ?.length ? (
              <div className="space-y-4">
                {data.topPages.map(
                  (
                    page,
                    index
                  ) => {
                    const maxViews =
                      data.topPages[0]
                        ?.views ??
                      1;

                    const percentage =
                      (page.views /
                        maxViews) *
                      100;

                    return (
                      <div
                        key={`${page.page}-${index}`}
                        className="group"
                      >
                        <div className="mb-1.5 flex items-center justify-between gap-4">
                          <div className="flex min-w-0 items-center gap-3">
                            <span className="flex h-7 w-7 shrink-0 items-center justify-center rounded-lg bg-gray-100 text-xs font-semibold text-gray-500">
                              {index +
                                1}
                            </span>

                            <span
                              className="truncate text-sm font-medium text-gray-700"
                              title={
                                page.page
                              }
                            >
                              {getPageName(
                                page.page
                              )}
                            </span>
                          </div>

                          <span className="shrink-0 text-sm font-semibold text-gray-900">
                            {formatNumber(
                              page.views
                            )}
                          </span>
                        </div>

                        <div className="ml-10 h-2 overflow-hidden rounded-full bg-gray-100">
                          <div
                            className="h-full rounded-full bg-gray-900 transition-all duration-500 group-hover:bg-gray-700"
                            style={{
                              width: `${percentage}%`,
                            }}
                          />
                        </div>

                        <p className="ml-10 mt-1 text-xs text-gray-400">
                          {page.page}
                        </p>
                      </div>
                    );
                  }
                )}
              </div>
            ) : (
              <EmptyState message="No page data available for this period." />
            )}
          </SectionCard>

          {/* -------------------------------- */}
          {/* DEVICE + BROWSER */}
          {/* -------------------------------- */}

          <div className="grid grid-cols-1 gap-6 lg:grid-cols-2">
            <SectionCard
              title="Devices"
              description="Page views by device type."
            >
              <BreakdownList
                items={
                  data?.devices ??
                  []
                }
                labelKey="device"
              />
            </SectionCard>

            <SectionCard
              title="Browsers"
              description="Page views by browser."
            >
              <BreakdownList
                items={
                  data?.browsers ??
                  []
                }
                labelKey="browser"
              />
            </SectionCard>
          </div>
        </>
      )}
    </div>
  );
}