"use client";

import type { ReactNode } from "react";
import NextLink from "next/link";

import CloseIcon from "@mui/icons-material/Close";
import EastIcon from "@mui/icons-material/East";
import {
  Avatar,
  Box,
  Button,
  Drawer,
  IconButton,
  Link,
  Typography,
} from "@mui/material";
import { alpha, useTheme } from "@mui/material/styles";

import { AppDivider } from "@/components/ui/divider";
import { formatDate, KHMER_DAY_PERIOD } from "@/lib/date-utils";
import { getDocumentUrl } from "@/lib/document-file";
import { getAvatarText } from "@/features/admin/user-management/components/table/user-table-cells";
import { getRoleLabel } from "@/features/auth/auth-data";

import {
  activityFieldLabels,
  actionLabels,
  actionVerbs,
  activityLogText,
  moduleLabels,
  moduleNouns,
  outcomeLabels,
} from "./activity-log-i18n";
import type { ActivityLog } from "./activity-log-types";

type ActivityText = (typeof activityLogText)["en"];

// Cambodia is always UTC+7 (no daylight saving).
const CAMBODIA_OFFSET_MINUTES = 7 * 60;

// Moves a time to Cambodia's clock, so the page shows Cambodia time whatever
// time zone the viewer's computer is set to.
export function toCambodiaTime(value: string) {
  const date = new Date(value);

  return new Date(
    date.getTime() +
      (CAMBODIA_OFFSET_MINUTES + date.getTimezoneOffset()) * 60_000,
  );
}

// A moment in Cambodia time, written with AM/PM. The period is worked out
// from the hour rather than formatted: date-fns' Khmer locale calls PM
// "ល្ងាច", while the app says "រសៀល" everywhere (KHMER_DAY_PERIOD).
export function formatActivityTime(
  value: string,
  language: Parameters<typeof formatDate>[1],
  withSeconds = false,
) {
  const date = toCambodiaTime(value);
  const period = date.getHours() < 12 ? "AM" : "PM";
  const time = formatDate(
    date,
    language,
    withSeconds ? "dd MMM yyyy, hh:mm:ss" : "dd MMM yyyy, hh:mm",
  );

  return `${time} ${language === "en" ? period : KHMER_DAY_PERIOD[period]}`;
}

// ---- Action badge --------------------------------------------------------
// One colour per kind of action, so the list can be scanned at a glance.

const ACTION_COLORS: Record<string, string> = {
  CREATE: "#12b76a",
  REGISTER: "#12b76a",
  LOGIN: "#12b76a",
  RESTORE: "#12b76a",
  PUBLISH: "#12b76a",
  GENERATE: "#12b76a",
  DELETE: "#f04438",
  REMOVE_ASSIGNMENT: "#f04438",
  UNSHARE: "#f04438",
  SUBMIT: "#444ce7",
  SEND: "#444ce7",
  SHARE: "#444ce7",
  REVIEW: "#f79009",
  SEND_BACK: "#f79009",
  EXPORT: "#7a5af8",
  LOGOUT: "#667085",
};
const DEFAULT_ACTION_COLOR = "#1570ef"; // updates and everything else
// A refused or failed attempt overrides the action colour, so it stands out.
const OUTCOME_COLORS: Record<string, string> = {
  DENIED: "#f04438",
  FAILED: "#f79009",
};

export function ActivityActionBadge({
  action,
  labelIndex,
  label,
  outcome,
}: {
  action: string;
  labelIndex: number;
  label?: string;
  // "DENIED" / "FAILED" turn the badge red / amber and add the outcome word.
  outcome?: string | null;
}) {
  const theme = useTheme();
  const failed = outcome && outcome !== "SUCCESS" ? outcome : null;
  const color =
    (failed && OUTCOME_COLORS[failed]) ??
    ACTION_COLORS[action] ??
    DEFAULT_ACTION_COLOR;
  const text = label ?? actionLabels[action]?.[labelIndex] ?? action;

  return (
    <Box
      component="span"
      sx={{
        display: "inline-flex",
        alignItems: "center",
        height: 24,
        px: 1,
        borderRadius: "999px",
        border: `1px solid ${alpha(color, 0.35)}`,
        bgcolor: alpha(color, theme.palette.mode === "dark" ? 0.18 : 0.08),
        color: theme.palette.mode === "dark" ? alpha("#ffffff", 0.9) : color,
        fontSize: 12,
        fontWeight: 600,
        whiteSpace: "nowrap",
      }}
    >
      {failed ? `${text} · ${outcomeLabels[failed]?.[labelIndex] ?? failed}` : text}
    </Box>
  );
}

// ---- Description ---------------------------------------------------------

// "Updated issue status", "Exported RGC decisions", "Logged in". Built from
// what is already stored (action, module, status change); nothing extra saved.
export function describeActivity(
  row: ActivityLog,
  labelIndex: number,
  text: ActivityText,
) {
  const verb = actionVerbs[row.action]?.[labelIndex] ?? row.action;
  if (row.module === "authentication") return verb;

  const noun =
    moduleNouns[row.module]?.[labelIndex] ??
    moduleLabels[row.module]?.[labelIndex] ??
    row.module;
  const hasStatusChange = Object.keys(row.changes ?? {}).some(
    (field) =>
      field === "status" ||
      field.endsWith("issueStatus.name") ||
      field.endsWith("meetingSummaryStatus.name"),
  );
  const statusPart =
    hasStatusChange && row.action !== "CREATE" ? ` ${text.statusWord}` : "";

  if (labelIndex === 0) {
    const subject = `${noun}${statusPart}`;
    return `${subject.charAt(0).toUpperCase()}${subject.slice(1)} ${verb.toLowerCase()}`;
  }
  return `${verb} ${noun}${statusPart}`;
}

// ---- Record links --------------------------------------------------------
// Only records an administrator can open get a link; the rest stay plain text.

export function getRecordLink(reference: string): string | null {
  const issue =
    /^(?:issues|working-group-issues)\/(\d+)(?:\/|$)/.exec(reference) ??
    /^(?:issues|working-group-issues) → #(\d+)$/.exec(reference);
  if (issue) return `/admin/issues-management/${issue[1]}`;

  const role = /^roles\/(\d+)/.exec(reference);
  if (role) return `/admin/role/${role[1]}`;

  const stakeholder = /^stakeholders\/(\d+)/.exec(reference);
  if (stakeholder) return `/admin/stakeholder/${stakeholder[1]}`;

  if (reference.startsWith("users/") || reference === "users") {
    return "/admin/user-management";
  }

  return null;
}

// "Issue #12 — Rice export quota": the record's kind and id, then the title
// or name it had when the action happened (when one was recorded).
export function getRecordLabel(
  row: ActivityLog,
  labelIndex: number,
  text: ActivityText,
) {
  const withName = (base: string) =>
    row.recordLabel ? `${base} — ${row.recordLabel}` : base;
  const issue =
    /^(?:issues|working-group-issues)(?:\/(\d+)(?:\/|$)| → #(\d+)$)/.exec(
      row.recordReference,
    );
  if (issue) return withName(`${text.issue} #${issue[1] ?? issue[2]}`);
  const record = /^([a-z-]+)(?:\/(\d+)$| → #(\d+)$)/.exec(row.recordReference);
  if (!record) return withName(row.recordReference);
  const name =
    moduleNouns[record[1]]?.[labelIndex] ??
    moduleLabels[record[1]]?.[labelIndex];
  return withName(
    name
      ? `${name.charAt(0).toUpperCase()}${name.slice(1)} #${record[2] ?? record[3]}`
      : row.recordReference,
  );
}

// ---- Details panel -------------------------------------------------------

function Section({ label, children }: { label: string; children: ReactNode }) {
  return (
    <Box>
      <Typography
        sx={{
          fontSize: 12,
          fontWeight: 600,
          color: "text.secondary",
          mb: 0.75,
        }}
      >
        {label}
      </Typography>
      {children}
    </Box>
  );
}

function InfoRow({ label, value }: { label: string; value: ReactNode }) {
  return (
    <Box
      sx={{
        display: "grid",
        gridTemplateColumns: "110px minmax(0, 1fr)",
        columnGap: 1.5,
        py: 0.5,
      }}
    >
      <Typography sx={{ fontSize: 13, color: "text.secondary" }}>
        {label}
      </Typography>
      <Typography sx={{ fontSize: 13, wordBreak: "break-word" }}>
        {value}
      </Typography>
    </Box>
  );
}

function displayChangeValue(
  value: string | null,
  language: Parameters<typeof formatDate>[1],
  text: ActivityText,
) {
  if (value === "true") return text.yes;
  if (value === "false") return text.booleanNo;
  if (value && /^\d{4}-\d{2}-\d{2}T/.test(value))
    return formatDate(toCambodiaTime(value), language, "dd MMM yyyy, HH:mm:ss");
  return value;
}

function ChangePill({ value }: { value: string | null }) {
  return (
    <Box
      component="span"
      sx={(theme) => ({
        display: "inline-flex",
        px: 1,
        py: 0.25,
        borderRadius: "999px",
        border: `1px solid ${theme.palette.divider}`,
        fontSize: 12,
        fontWeight: 500,
        maxWidth: "100%",
        overflowWrap: "anywhere",
      })}
    >
      {value ?? "-"}
    </Box>
  );
}

type ActivityLogDetailsDrawerProps = {
  row: ActivityLog | null;
  // The app language, in the form the shared date formatter expects.
  language: Parameters<typeof formatDate>[1];
  onClose: () => void;
  // Narrows the list to every activity on this row's record. Left out (on a
  // record's own history), the button is not shown.
  onViewHistory?: (reference: string) => void;
};

export function ActivityLogDetailsDrawer({
  row,
  language,
  onClose,
  onViewHistory,
}: ActivityLogDetailsDrawerProps) {
  const theme = useTheme();
  const isDark = theme.palette.mode === "dark";
  const text = activityLogText[language === "en" ? "en" : "kh"];
  const labelIndex = language === "en" ? 0 : 1;
  const recordLink = row ? getRecordLink(row.recordReference) : null;

  return (
    <Drawer
      anchor="right"
      open={Boolean(row)}
      onClose={onClose}
      sx={{
        "& .MuiBackdrop-root": { bgcolor: "rgba(0, 0, 0, 0.35)" },
        "& .MuiDrawer-paper": {
          width: { xs: "100vw", sm: 440 },
          maxWidth: "100vw",
          height: "100dvh",
          borderRadius: { xs: 0, sm: "12px 0 0 12px" },
          bgcolor: isDark ? "#101828" : "#ffffff",
          backgroundImage: "none",
          display: "flex",
          flexDirection: "column",
        },
      }}
    >
      {row ? (
        <>
          {/* Header */}
          <Box
            sx={{
              px: 2.5,
              py: 2,
              display: "flex",
              alignItems: "center",
              justifyContent: "space-between",
              borderBottom: `1px solid ${theme.palette.divider}`,
            }}
          >
            <Typography sx={{ fontSize: 18, fontWeight: 700 }}>
              {text.details}
            </Typography>
            <IconButton aria-label={text.close} onClick={onClose} size="small">
              <CloseIcon fontSize="small" />
            </IconButton>
          </Box>

          {/* Content stays at its natural height; the body scrolls on small screens. */}
          <Box sx={{ flex: 1, minHeight: 0, overflowY: "auto" }}>
            <Box sx={{ p: 2.5 }}>
              <ActivityActionBadge
                action={row.action}
                labelIndex={labelIndex}
                label={actionVerbs[row.action]?.[labelIndex]}
                outcome={row.outcome}
              />
              <Typography
                sx={{ mt: 1.5, mb: 3, fontSize: 18, fontWeight: 700 }}
              >
                {describeActivity(row, labelIndex, text)}
              </Typography>
              <Typography
                sx={{
                  fontSize: 11,
                  fontWeight: 700,
                  color: "text.secondary",
                  textTransform: "uppercase",
                  letterSpacing: language === "en" ? 0.7 : 0,
                  mb: 2.5,
                }}
              >
                {text.activityInformation}
              </Typography>
              <Box sx={{ display: "flex", flexDirection: "column", gap: 2.5 }}>
                <Section label={text.user}>
                  <Box
                    sx={{ display: "flex", alignItems: "center", gap: 1.25 }}
                  >
                    <Avatar
                      src={
                        row.actorAvatar
                          ? getDocumentUrl(row.actorAvatar)
                          : undefined
                      }
                      alt={row.actorName}
                      sx={{
                        width: 40,
                        height: 40,
                        fontSize: 14,
                        fontWeight: 700,
                        color: "primary.main",
                        bgcolor: alpha(theme.palette.primary.main, 0.1),
                      }}
                    >
                      {getAvatarText(row.actorName)}
                    </Avatar>
                    <Box sx={{ minWidth: 0 }}>
                      <Typography sx={{ fontSize: 14, fontWeight: 600 }}>
                        {row.actorName}
                      </Typography>
                      <Typography
                        sx={{ fontSize: 13, color: "text.secondary" }}
                      >
                        {row.actorOrganization?.name ||
                          row.actorRoles.map(getRoleLabel).join(", ") ||
                          "—"}{" "}
                        · #{row.actorId}
                      </Typography>
                    </Box>
                  </Box>
                </Section>
                <Section label={text.dateTime}>
                  <Typography sx={{ fontSize: 14 }}>
                    {formatActivityTime(row.createdAt, language, true)}
                  </Typography>
                </Section>
                <Section label={text.module}>
                  <Typography sx={{ fontSize: 14 }}>
                    {moduleLabels[row.module]?.[labelIndex] ?? row.module}
                  </Typography>
                </Section>
                <Section label={text.record}>
                  <Box
                    sx={{
                      display: "flex",
                      alignItems: "baseline",
                      justifyContent: "space-between",
                      gap: 2,
                    }}
                  >
                    <Typography sx={{ fontSize: 14, overflowWrap: "anywhere" }}>
                      {getRecordLabel(row, labelIndex, text)}
                    </Typography>
                    {recordLink && row.action !== "DELETE" ? (
                      <Link
                        component={NextLink}
                        href={recordLink}
                        sx={{
                          display: "inline-flex",
                          alignItems: "center",
                          gap: 0.5,
                          fontSize: 13,
                          flexShrink: 0,
                        }}
                      >
                        {text.view}
                        <EastIcon sx={{ fontSize: 15 }} />
                      </Link>
                    ) : null}
                  </Box>
                </Section>
              </Box>
            </Box>

            <AppDivider />
            <Box sx={{ p: 2.5 }}>
              <Typography
                sx={{
                  fontSize: 11,
                  fontWeight: 700,
                  color: "text.secondary",
                  textTransform: "uppercase",
                  mb: 2,
                }}
              >
                {row.module === "authentication" || row.action === "EXPORT"
                  ? text.actionSummary
                  : text.changes}
              </Typography>
              <Box sx={{ display: "flex", flexDirection: "column", gap: 2.5 }}>
                {Object.entries(row.changes ?? {})
                  .filter(([key]) => key !== "_outcome")
                  .map(([field, change]) => (
                    <Section
                      key={field}
                      label={field
                        .split(".")
                        .map(
                          (part) =>
                            activityFieldLabels[part]?.[labelIndex] ?? part,
                        )
                        .join(" · ")}
                    >
                      {change.kind &&
                      ["added", "removed", "changed"].includes(change.kind) ? (
                        <Typography sx={{ fontSize: 14 }}>
                          {text[change.kind as "added" | "removed" | "changed"]}
                        </Typography>
                      ) : (
                        <Box
                          sx={{
                            display: "flex",
                            alignItems: "center",
                            gap: 1,
                            flexWrap: "wrap",
                            overflowWrap: "anywhere",
                          }}
                        >
                          <ChangePill
                            value={displayChangeValue(
                              change.from,
                              language,
                              text,
                            )}
                          />
                          <EastIcon
                            sx={{ fontSize: 16, color: "text.secondary" }}
                          />
                          <ChangePill
                            value={displayChangeValue(
                              change.to,
                              language,
                              text,
                            )}
                          />
                        </Box>
                      )}
                    </Section>
                  ))}
                {row.changes?._outcome ? (
                  <Typography sx={{ fontSize: 13, color: "text.secondary" }}>
                    {row.changes._outcome.to === "UNCHANGED"
                      ? text.unchanged
                      : row.changes._outcome.to === "UNAVAILABLE"
                        ? text.unavailable
                        : row.changes._outcome.to === "DENIED" ||
                            row.changes._outcome.to === "FAILED"
                          ? // A refused or failed attempt changed nothing.
                            text.notApplied
                          : (actionVerbs[
                              row.changes._outcome.to ?? row.action
                            ]?.[labelIndex] ?? row.action)}
                  </Typography>
                ) : !Object.keys(row.changes ?? {}).length ? (
                  <Typography sx={{ fontSize: 13, color: "text.secondary" }}>
                    {row.module === "authentication" || row.action === "EXPORT"
                      ? describeActivity(row, labelIndex, text)
                      : text.noChanges}
                  </Typography>
                ) : null}
              </Box>
            </Box>

            <AppDivider />
            <Box sx={{ p: 2.5 }}>
              <Typography
                sx={{
                  fontSize: 11,
                  fontWeight: 700,
                  color: "text.secondary",
                  textTransform: "uppercase",
                  mb: 2,
                }}
              >
                {text.requestInfo}
              </Typography>
              {row.outcome && row.outcome !== "SUCCESS" ? (
                <>
                  <InfoRow
                    label={text.outcome}
                    value={`${outcomeLabels[row.outcome]?.[labelIndex] ?? row.outcome}${
                      row.statusCode
                        ? ` (${text.statusCode} ${row.statusCode})`
                        : ""
                    }`}
                  />
                  {/* What went wrong, when the action reported a reason. */}
                  {row.errorMessage ? (
                    <InfoRow
                      label={text.errorReason}
                      value={row.errorMessage}
                    />
                  ) : null}
                </>
              ) : null}
              <InfoRow
                label={text.ipAddress}
                value={row.ipAddress ?? text.notRecorded}
              />
              <InfoRow
                label={text.method}
                value={row.method ?? text.notRecorded}
              />
              <InfoRow
                label={text.endpoint}
                value={row.endpoint ?? text.notRecorded}
              />
              <Box sx={{ mt: 2 }}>
                <Section label={text.userAgent}>
                  <Typography sx={{ fontSize: 13, overflowWrap: "anywhere" }}>
                    {row.userAgent ?? text.notRecorded}
                  </Typography>
                </Section>
              </Box>
            </Box>
          </Box>

          {/* Footer */}
          <Box
            sx={{
              px: 2.5,
              py: 2,
              display: "flex",
              justifyContent: "flex-end",
              gap: 1.5,
              borderTop: `1px solid ${theme.palette.divider}`,
            }}
          >
            <Button variant="outlined" onClick={onClose}>
              {text.close}
            </Button>
            {onViewHistory ? (
              <Button
                variant="contained"
                onClick={() => onViewHistory(row.recordReference)}
              >
                {text.fullHistory}
              </Button>
            ) : null}
          </Box>
        </>
      ) : null}
    </Drawer>
  );
}
