import {
  AppProvider as PolarisAppProvider,
  Badge,
  BlockStack,
  Box,
  Card,
  ChoiceList,
  EmptyState,
  Icon,
  IndexFilters,
  IndexFiltersMode,
  IndexTable,
  Modal,
  Page,
  Pagination,
  TextContainer,
  Text,
  Tooltip,
  useSetIndexFiltersMode,
} from "@shopify/polaris";
import { useLoaderData, useNavigate, useNavigation } from "react-router";
import { useEffect, useState } from "react";
import enTranslations from "@shopify/polaris/locales/en.json";
import { ViewIcon } from "@shopify/polaris-icons";
import { authenticate } from "../shopify.server";
import {
  countAppEventLogs,
  listAppEventLogs,
  listAppEventLogSources,
} from "../models.app-event-log.server";

export const loader = async ({ request }) => {
  const { session } = await authenticate.admin(request);
  const url = new URL(request.url);
  const source = url.searchParams.get("source") || "";
  const level = url.searchParams.get("level") || "";
  const query = url.searchParams.get("query") || "";
  const page = Math.max(1, Number(url.searchParams.get("page") || 1));
  const pageSize = 20;
  const offset = (page - 1) * pageSize;

  try {
    const [logs, totalCount, sources] = await Promise.all([
      listAppEventLogs(session.shop, {
        limit: pageSize,
        offset,
        source,
        level,
        query,
      }),
      countAppEventLogs(session.shop, { source, level, query }),
      listAppEventLogSources(session.shop),
    ]);
    return {
      logs,
      totalCount,
      page,
      pageSize,
      sources,
      selectedSource: source,
      selectedLevel: level,
      selectedQuery: query,
      error: null,
    };
  } catch (error) {
    return {
      logs: [],
      totalCount: 0,
      page,
      pageSize,
      sources: [],
      selectedSource: source,
      selectedLevel: level,
      selectedQuery: query,
      error:
        error instanceof Error
          ? error.message
          : "Unable to load activity logs.",
    };
  }
};

function levelTone(level) {
  switch (level) {
    case "error":
      return "critical";
    case "warning":
      return "warning";
    case "success":
      return "success";
    default:
      return "info";
  }
}

function shortValue(value, maxLength = 60) {
  if (!value) return "Not captured";
  if (value.length <= maxLength) return value;
  return `${value.slice(0, maxLength)}...`;
}

function buildLogsUrl({ source, level, query, page }) {
  const params = new URLSearchParams();
  if (source) params.set("source", source);
  if (level) params.set("level", level);
  if (query) params.set("query", query);
  if (page > 1) params.set("page", String(page));
  const queryString = params.toString();
  return queryString
    ? `/app/activity-logs?${queryString}`
    : "/app/activity-logs";
}

export default function ActivityLogsPage() {
  const {
    logs,
    error,
    sources,
    selectedSource,
    selectedLevel,
    selectedQuery,
    totalCount,
    page,
    pageSize,
  } = useLoaderData();
  const navigation = useNavigation();
  const navigate = useNavigate();
  const { mode, setMode } = useSetIndexFiltersMode(IndexFiltersMode.Filtering);
  const [sourceFilter, setSourceFilter] = useState(selectedSource);
  const [levelFilter, setLevelFilter] = useState(selectedLevel);
  const [queryValue, setQueryValue] = useState(selectedQuery);
  const [activeLog, setActiveLog] = useState(null);

  useEffect(() => {
    setSourceFilter(selectedSource);
    setLevelFilter(selectedLevel);
    setQueryValue(selectedQuery);
  }, [selectedSource, selectedLevel, selectedQuery]);

  useEffect(() => {
    const normalizedQuery = queryValue.trim();

    if (normalizedQuery === selectedQuery) {
      return undefined;
    }

    const timer = setTimeout(() => {
      applyFilters({ query: normalizedQuery, nextPage: 1 });
    }, 450);

    return () => clearTimeout(timer);
  }, [queryValue]);

  const sourceOptions = [
    { label: "All extensions", value: "__all__" },
    ...sources.map((entry) => ({
      label: entry.extensionTarget
        ? `${entry.source} (${entry.extensionTarget})`
        : entry.source,
      value: entry.source,
    })),
  ];

  const levelOptions = [
    { label: "All levels", value: "__all__" },
    { label: "Error", value: "error" },
    { label: "Warning", value: "warning" },
    { label: "Success", value: "success" },
    { label: "Info", value: "info" },
  ];

  const hasPreviousPage = page > 1;
  const hasNextPage = page * pageSize < totalCount;
  const paginationLabel =
    totalCount > 0
      ? `${(page - 1) * pageSize + 1}-${Math.min(page * pageSize, totalCount)} of ${totalCount}`
      : "0 logs";

  const applyFilters = ({
    source = sourceFilter,
    level = levelFilter,
    query = queryValue,
    nextPage = 1,
  }) => {
    navigate(
      buildLogsUrl({
        source,
        level,
        query,
        page: nextPage,
      }),
    );
  };

  const handleSourceChange = (value) => {
    const nextSource = value[0] === "__all__" ? "" : value[0] || "";
    setSourceFilter(nextSource);
    applyFilters({
      source: nextSource,
      level: levelFilter,
      query: queryValue,
      nextPage: 1,
    });
  };

  const handleLevelChange = (value) => {
    const nextLevel = value[0] === "__all__" ? "" : value[0] || "";
    setLevelFilter(nextLevel);
    applyFilters({
      source: sourceFilter,
      level: nextLevel,
      query: queryValue,
      nextPage: 1,
    });
  };

  const handleQueryChange = (value) => {
    setQueryValue(value);
  };

  const handleQuerySubmit = () => {
    applyFilters({ query: queryValue.trim(), nextPage: 1 });
  };

  const handleQueryClear = () => {
    setQueryValue("");
    applyFilters({ query: "", nextPage: 1 });
  };

  const appliedFilters = [];

  if (selectedSource) {
    appliedFilters.push({
      key: "source",
      label: `Extension: ${selectedSource}`,
      onRemove: () => {
        setSourceFilter("");
        applyFilters({ source: "", level: selectedLevel, nextPage: 1 });
      },
    });
  }

  if (selectedLevel) {
    appliedFilters.push({
      key: "level",
      label: `Level: ${selectedLevel}`,
      onRemove: () => {
        setLevelFilter("");
        applyFilters({ source: selectedSource, level: "", nextPage: 1 });
      },
    });
  }

  if (selectedQuery) {
    appliedFilters.push({
      key: "query",
      label: `Search: ${selectedQuery}`,
      onRemove: () => {
        setQueryValue("");
        applyFilters({
          source: selectedSource,
          level: selectedLevel,
          query: "",
          nextPage: 1,
        });
      },
    });
  }

  const filters = [
    {
      key: "source",
      label: "Extension",
      filter: (
        <ChoiceList
          title="Extension"
          titleHidden
          choices={sourceOptions}
          selected={[sourceFilter || "__all__"]}
          onChange={handleSourceChange}
        />
      ),
      shortcut: true,
    },
    {
      key: "level",
      label: "Level",
      filter: (
        <ChoiceList
          title="Level"
          titleHidden
          choices={levelOptions}
          selected={[levelFilter || "__all__"]}
          onChange={handleLevelChange}
        />
      ),
      shortcut: true,
    },
  ];

  return (
    <PolarisAppProvider i18n={enTranslations}>
      <Page
        fullWidth
        title="Activity Logs"
        subtitle="Track checkout extension events, customer actions, and errors."
      >
        <Card>
          <IndexFilters
            tabs={[{ id: "all-logs", content: "All logs" }]}
            selected={0}
            onSelect={() => {}}
            mode={mode}
            setMode={setMode}
            filters={filters}
            appliedFilters={appliedFilters}
            onClearAll={() => {
              setSourceFilter("");
              setLevelFilter("");
              setQueryValue("");
              navigate("/app/activity-logs");
            }}
            queryValue={queryValue}
            queryPlaceholder="Search checkout Token, customer, event, or message"
            onQueryChange={handleQueryChange}
            onQueryClear={handleQueryClear}
            onQueryBlur={handleQuerySubmit}
            loading={navigation.state === "loading"}
            disableKeyboardShortcuts
          />
          {error ? (
            <BlockStack gap="300">
              <Text as="p" variant="headingSm">
                Activity logs are not available yet.
              </Text>
              <Text as="p" tone="subdued">
                {error}
              </Text>
              <Text as="p" tone="subdued">
                On production, run the latest Prisma migration so the
                `AppEventLog` table is created, then redeploy/restart the app.
              </Text>
            </BlockStack>
          ) : !logs.length ? (
            <EmptyState heading="No logs yet">
              <p>
                Logs from checkout extensions and backend tracking will appear
                here once customers start interacting with the app.
              </p>
            </EmptyState>
          ) : (
            <BlockStack gap="300">
              <Text as="p" tone="subdued">
                Showing {paginationLabel}
              </Text>
              <IndexTable
                resourceName={{ singular: "log", plural: "logs" }}
                itemCount={logs.length}
                selectable={false}
                headings={[
                  { title: "Event" },

                  { title: "Checkout Token" },
                  { title: "Customer details" },
                  { title: "IP / User agent" },
                  { title: "Created" },
                  { title: "View" },
                ]}
              >
                {logs.map((log, index) => (
                  <IndexTable.Row
                    id={String(log.id)}
                    key={log.id}
                    position={index}
                  >
                    <IndexTable.Cell>
                      <BlockStack gap="100">
                        <Text as="span" variant="bodyMd" fontWeight="semibold">
                          {log.eventType}{" "}
                          <Badge tone={levelTone(log.level)}>{log.level}</Badge>
                        </Text>
                        {log.message ? (
                          <Text as="span" tone="subdued">
                            {shortValue(log.message, 100)}
                          </Text>
                        ) : null}

                        <Text as="span">Extension :- {log.source}</Text>
                        <Text as="span">
                          {log.extensionTarget || "Not captured"}
                        </Text>
                      </BlockStack>
                    </IndexTable.Cell>

                    <IndexTable.Cell>
                      <Text as="span">
                        {log.checkoutToken || "Not captured"}
                      </Text>
                    </IndexTable.Cell>

                    <IndexTable.Cell>
                      <BlockStack gap="100">
                        <Text as="span">
                          {log.customerName || "Name not captured"}
                        </Text>
                        <Text as="span" tone="subdued">
                          {log.customerEmail || "Email not captured"}
                        </Text>
                        {log.customerId ? (
                          <Text as="span" tone="subdued">
                            {shortValue(log.customerId, 42)}
                          </Text>
                        ) : null}
                      </BlockStack>
                    </IndexTable.Cell>

                    <IndexTable.Cell>
                      <BlockStack gap="100">
                        <Text as="span">{log.ipAddress || "Not captured"}</Text>
                        <Text as="span" tone="subdued">
                          {shortValue(log.userAgent, 60)}
                        </Text>
                      </BlockStack>
                    </IndexTable.Cell>
                    <IndexTable.Cell>
                      <Text as="span">
                        {new Date(log.createdAt).toLocaleString("en-IN")}
                      </Text>
                    </IndexTable.Cell>
                    <IndexTable.Cell>
                      <Tooltip content="View log details">
                        <button
                          type="button"
                          onClick={() => setActiveLog(log)}
                          style={{
                            border: "none",
                            background: "transparent",
                            padding: "4px",
                            cursor: "pointer",
                            display: "inline-flex",
                            alignItems: "center",
                            justifyContent: "center",
                          }}
                          aria-label={`View details for ${log.eventType}`}
                        >
                          <Icon source={ViewIcon} tone="base" />
                        </button>
                      </Tooltip>
                    </IndexTable.Cell>
                  </IndexTable.Row>
                ))}
              </IndexTable>
              <Pagination
                hasPrevious={hasPreviousPage}
                onPrevious={() => {
                  navigate(
                    buildLogsUrl({
                      source: selectedSource,
                      level: selectedLevel,
                      query: selectedQuery,
                      page: page - 1,
                    }),
                  );
                }}
                hasNext={hasNextPage}
                onNext={() => {
                  navigate(
                    buildLogsUrl({
                      source: selectedSource,
                      level: selectedLevel,
                      query: selectedQuery,
                      page: page + 1,
                    }),
                  );
                }}
                label={paginationLabel}
              />
            </BlockStack>
          )}
        </Card>
        <Modal
          open={Boolean(activeLog)}
          onClose={() => setActiveLog(null)}
          title={activeLog ? activeLog.eventType : "Log details"}
          primaryAction={{
            content: "Close",
            onAction: () => setActiveLog(null),
          }}
        >
          <Modal.Section>
            {activeLog ? (
              <BlockStack gap="400">
                <InlineLogRow label="Extension" value={activeLog.source} />
                <InlineLogRow
                  label="Target"
                  value={activeLog.extensionTarget || "Not captured"}
                />
                <InlineLogRow label="Level" value={activeLog.level} />
                <InlineLogRow
                  label="Created"
                  value={new Date(activeLog.createdAt).toLocaleString("en-IN")}
                />
                <InlineLogRow
                  label="Customer name"
                  value={activeLog.customerName || "Not captured"}
                />
                <InlineLogRow
                  label="Customer email"
                  value={activeLog.customerEmail || "Not captured"}
                />
                <InlineLogRow
                  label="Customer ID"
                  value={activeLog.customerId || "Not captured"}
                />
                <InlineLogRow
                  label="Checkout token"
                  value={activeLog.checkoutToken || "Not captured"}
                />
                <InlineLogRow
                  label="IP address"
                  value={activeLog.ipAddress || "Not captured"}
                />
                <InlineLogRow
                  label="User agent"
                  value={activeLog.userAgent || "Not captured"}
                />
                <InlineLogRow
                  label="Message"
                  value={activeLog.message || "No message"}
                />
                <TextContainer>
                  <Text as="p" variant="headingSm">
                    Payload
                  </Text>
                  <Box
                    as="pre"
                    padding="300"
                    background="bg-surface-secondary"
                    borderRadius="200"
                    overflowX="auto"
                  >
                    {activeLog.payload
                      ? JSON.stringify(activeLog.payload, null, 2)
                      : "No payload"}
                  </Box>
                </TextContainer>
              </BlockStack>
            ) : null}
          </Modal.Section>
        </Modal>
      </Page>
    </PolarisAppProvider>
  );
}

function InlineLogRow({ label, value }) {
  return (
    <BlockStack gap="100">
      <Text as="p" variant="headingSm">
        {label}
      </Text>
      <Text as="p" tone="subdued">
        {value}
      </Text>
    </BlockStack>
  );
}
