"use client";

import { useCallback, useEffect, useMemo, useState } from "react";
import {
  Alert,
  Avatar,
  Button,
  Card,
  Col,
  DatePicker,
  Descriptions,
  Divider,
  Drawer,
  Collapse,
  Form,
  Input,
  Row,
  Select,
  Space,
  Spin,
  Table,
  Tabs,
  Tag,
  Tooltip,
  Typography,
} from "antd";
import { FilterOutlined, ReloadOutlined } from "@ant-design/icons";
import dayjs from "dayjs";
import { usePathname, useRouter, useSearchParams } from "next/navigation";

import DepartmentDropdown from "@/components/common/DepartmentDropdown";
import EmployeeDropdown from "@/components/common/EmployeeDropdown";
import { fetchAuditLog } from "@/lib/api/audit";
import { fetchEmployee } from "@/lib/api/employees";
import { useAuditLogs } from "@/lib/hooks/use-audit-logs";
import type { AuditLog, AuditLogFilters } from "@/types/audit";

const { RangePicker } = DatePicker;
const { Text, Title } = Typography;

const RESOURCE_OPTIONS = [
  { label: "System Settings", value: "system_settings" },
  { label: "User", value: "user" },
  { label: "Role", value: "role" },
  { label: "CAASM", value: "caasm_asset" },
  { label: "Sync Job", value: "sync_job" },
  { label: "Vulnerability", value: "vuln_finding" },
];

// Values must mirror what the backend actually writes into audit_logs.action:
// the audit middleware records the HTTP method (GET/POST/…) for generic calls
// (internal/middleware/audit_trail.go), while a few flows write semantic dotted
// actions (auth.login.<provider>, system.settings.update, …). The backend
// filters by exact match, so keep this list aligned with the writers.
const ACTION_OPTIONS = [
  { label: "GET", value: "GET" },
  { label: "POST", value: "POST" },
  { label: "PUT", value: "PUT" },
  { label: "PATCH", value: "PATCH" },
  { label: "DELETE", value: "DELETE" },
  { label: "Login (Google)", value: "auth.login.google" },
  { label: "Login (Auth0)", value: "auth.login.auth0" },
  { label: "Logout", value: "auth.logout" },
  { label: "Token Refresh", value: "auth.refresh" },
  { label: "Settings Update", value: "system.settings.update" },
  { label: "Assign Roles", value: "user.assign_roles" },
  { label: "Remove Role", value: "user.remove_role" },
  { label: "Link Employee", value: "user.link_employee" },
  { label: "Role Delete", value: "role.delete" },
  { label: "Assign Permissions", value: "role.assign_permissions" },
  { label: "Retention Cleanup", value: "retention_cleanup" },
];

const { Panel } = Collapse;

// Tabs above the records table filter audit rows by actor_type.
// "all" omits the actor_type query param entirely.
const ACTOR_TYPE_TABS = [
  { key: "all", label: "All" },
  { key: "user", label: "Human" },
  { key: "agent", label: "Agent" },
];

function summarizeUserAgent(value?: string): string {
  if (!value) {
    return "-";
  }

  const normalized = value.replace(/\s+/g, " ").trim();
  const collapsed = normalized.replace(/^Mozilla\/5\.0\s*/i, "");
  if (collapsed.length <= 72) {
    return collapsed;
  }
  return `${collapsed.slice(0, 69)}...`;
}

export default function AuditLogsPage() {
  const searchParams = useSearchParams();
  const pathname = usePathname();
  const router = useRouter();
  const [form] = Form.useForm();

  const [drawerVisible, setDrawerVisible] = useState(false);
  const [drawerLoading, setDrawerLoading] = useState(false);
  const [selectedLog, setSelectedLog] = useState<AuditLog | null>(null);
  const [selectedEmployeeId, setSelectedEmployeeId] = useState<number | undefined>(undefined);
  const [selectedEmployeeEmail, setSelectedEmployeeEmail] = useState<string | undefined>(undefined);

  const initialFilters = useMemo<AuditLogFilters>(() => {
    const params: AuditLogFilters = {};
    const resourceType = searchParams?.get("resource_type");
    const userID = searchParams?.get("user_id");
    const action = searchParams?.get("action");
    const keyword = searchParams?.get("keyword");
    const actorEmail = searchParams?.get("actor_email");
    const actorType = searchParams?.get("actor_type");
    const departmentId = searchParams?.get("department_id");
    if (resourceType) params.resource_type = resourceType;
    if (userID) params.user_id = userID;
    if (actorEmail) params.actor_email = actorEmail;
    if (actorType) params.actor_type = actorType;
    if (departmentId) params.department_id = departmentId;
    if (action) params.action = action;
    if (keyword) params.keyword = keyword;
    const fromParam = searchParams?.get("from");
    const toParam = searchParams?.get("to");
    if (fromParam) params.from = fromParam;
    if (toParam) params.to = toParam;
    return params;
  }, [searchParams]);

  const { logs, pagination, filters, loading, error, refresh } = useAuditLogs(initialFilters);

  useEffect(() => {
    if (!filters.from || !filters.to) {
      const defaultFrom = dayjs().subtract(7, "day").toISOString();
      const defaultTo = dayjs().toISOString();
      void refresh({ from: filters.from ?? defaultFrom, to: filters.to ?? defaultTo });
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  useEffect(() => {
    const range = [filters.from ? dayjs(filters.from) : null, filters.to ? dayjs(filters.to) : null] as [dayjs.Dayjs | null, dayjs.Dayjs | null];
    form.setFieldsValue({
      user_id: filters.user_id,
      resource_type: filters.resource_type,
      action: filters.action,
      keyword: filters.keyword,
      department_id: filters.department_id,
      date_range: range[0] && range[1] ? range : undefined,
    });
    if (filters.actor_email && filters.actor_email !== selectedEmployeeEmail) {
      setSelectedEmployeeEmail(filters.actor_email);
    }
  }, [filters, form, selectedEmployeeEmail]);

  const handleEmployeeFilterChange = async (value?: number) => {
    const nextValue = value ?? undefined;
    setSelectedEmployeeId(nextValue);
    if (!nextValue) {
      setSelectedEmployeeEmail(undefined);
      return;
    }
    try {
      const emp = await fetchEmployee(nextValue);
      setSelectedEmployeeEmail(emp?.email || undefined);
    } catch {
      setSelectedEmployeeEmail(undefined);
    }
  };

  const handleFilterSubmit = async () => {
    const values = await form.validateFields();
    const nextFilters: AuditLogFilters = {
      ...filters,
      user_id: values.user_id || undefined,
      actor_email: selectedEmployeeEmail,
      department_id: values.department_id || undefined,
      resource_type: values.resource_type || undefined,
      action: values.action || undefined,
      keyword: values.keyword || undefined,
      page: 1,
    };
    if (values.date_range && values.date_range.length === 2) {
      nextFilters.from = values.date_range[0]?.toISOString();
      nextFilters.to = values.date_range[1]?.toISOString();
    } else {
      nextFilters.from = undefined;
      nextFilters.to = undefined;
    }
    await refresh(nextFilters);
    const next = new URLSearchParams();
    Object.entries(nextFilters).forEach(([key, value]) => {
      if (value) {
        next.set(key, String(value));
      }
    });
    router.replace(`${pathname}?${next.toString()}`);
  };

  const handleReset = async () => {
    form.resetFields();
    setSelectedEmployeeId(undefined);
    setSelectedEmployeeEmail(undefined);
    const defaultRange = [dayjs().subtract(7, "day"), dayjs()];
    form.setFieldsValue({ date_range: defaultRange });
    await refresh({
      page: 1,
      user_id: undefined,
      actor_email: undefined,
      department_id: undefined,
      action: undefined,
      resource_type: undefined,
      keyword: undefined,
      from: defaultRange[0].toISOString(),
      to: defaultRange[1].toISOString(),
    });
  };

  const handlePageChange = (page: number, pageSize?: number) => {
    void refresh({ ...filters, page, page_size: pageSize });
  };

  const actorTypeTab = filters.actor_type ?? "all";

  const handleActorTypeTabChange = (key: string) => {
    const nextFilters: AuditLogFilters = {
      ...filters,
      actor_type: key === "all" ? undefined : key,
      page: 1,
    };
    void refresh(nextFilters);
    const next = new URLSearchParams();
    Object.entries(nextFilters).forEach(([name, value]) => {
      if (value) {
        next.set(name, String(value));
      }
    });
    router.replace(`${pathname}?${next.toString()}`);
  };

  const handleRowClick = useCallback(async (record: AuditLog) => {
    setSelectedLog(record);
    setDrawerVisible(true);
    setDrawerLoading(true);
    try {
      const data = await fetchAuditLog(record.id);
      setSelectedLog(data);
    } catch (error) {
      console.error("Failed to load audit log details:", error);
    } finally {
      setDrawerLoading(false);
    }
  }, []);

  const columns = [
    {
      title: "Action",
      dataIndex: "action",
      key: "action",
      render: (value: string) => <Tag color="blue">{value}</Tag>,
    },
    {
      title: "Resource",
      dataIndex: "resource_type",
      key: "resource_type",
      render: (_: string, record: AuditLog) => (
        <Space direction="vertical" size={0}>
          <Text>{record.resource_type || "n/a"}</Text>
          <Text type="secondary">{record.resource_id || "-"}</Text>
        </Space>
      ),
    },
    {
      title: "Actor",
      dataIndex: "actor_email",
      key: "actor",
      render: (_: string, record: AuditLog) => {
        // Agent (API key / MCP) calls carry no email: identify them via the
        // agent attribution in metadata instead of falling through to "System".
        if (record.actor_type === "agent") {
          const meta = record.metadata as Record<string, unknown> | undefined;
          const agentName =
            (typeof meta?.agent_name === "string" && meta.agent_name) ||
            (meta?.agent_id ? `Key #${meta.agent_id}` : "Agent");
          return (
            <Space direction="vertical" size={0}>
              <Space size={6}>
                <Text>{agentName}</Text>
                <Tag color="geekblue" style={{ marginInlineEnd: 0 }}>
                  Agent
                </Tag>
              </Space>
              {record.actor_user_id ? (
                <Text type="secondary" style={{ fontSize: 12 }}>
                  owner: User #{record.actor_user_id}
                </Text>
              ) : null}
            </Space>
          );
        }
        const employee = record.actor_employee;
        const user = record.actor_user;
        const label = employee?.name || user?.name || record.actor_email || "System";
        const secondary =
          employee?.department_name ||
          employee?.department_id ||
          record.actor_email ||
          (record.actor_user_id ? `User #${record.actor_user_id}` : undefined);
        return (
          <Space size={8}>
            {employee?.avatar_url || user?.avatar_url ? (
              <Avatar size="small" src={employee?.avatar_url || user?.avatar_url} />
            ) : null}
            <Space direction="vertical" size={0}>
              <Text>{label}</Text>
              {secondary ? (
                <Text type="secondary" style={{ fontSize: 12 }}>
                  {secondary}
                </Text>
              ) : null}
            </Space>
          </Space>
        );
      },
    },
    {
      title: "Client",
      dataIndex: "ip_address",
      key: "ip_address",
      render: (_: string, record: AuditLog) => (
        <Space direction="vertical" size={0} style={{ maxWidth: 240 }}>
          <Text strong>{record.ip_address || "-"}</Text>
          <Tooltip title={record.user_agent || "No user agent provided"}>
            <Text
              type="secondary"
              style={{ fontSize: 12, display: "block" }}
              ellipsis={{ tooltip: record.user_agent || "No user agent provided" }}
            >
              {summarizeUserAgent(record.user_agent)}
            </Text>
          </Tooltip>
        </Space>
      ),
    },
    {
      title: "Time (UTC)",
      dataIndex: "created_at",
      key: "created_at",
      render: (value: string) => (
        <Space direction="vertical" size={0}>
          <Text>{dayjs(value).format("YYYY-MM-DD HH:mm:ss")}</Text>
          <Text type="secondary" style={{ fontSize: 12 }}>
            UTC
          </Text>
        </Space>
      ),
    },
    {
      title: "Operations",
      key: "actions",
      render: (_: unknown, record: AuditLog) => (
        <Button type="link" onClick={() => handleRowClick(record)}>
          Details
        </Button>
      ),
    },
  ];

  return (
    <Space direction="vertical" size={16} style={{ width: "100%" }}>
      <div>
        <Title level={3} style={{ marginBottom: 0 }}>
          Audit Trail
        </Title>
      </div>

      {/* Search and Filter Card */}
      <Card>
        <Form layout="vertical" form={form} onFinish={handleFilterSubmit}>
          <Row gutter={16}>
            <Col xs={24} md={12} lg={8}>
              <Form.Item label="Date Range" name="date_range">
                <RangePicker
                  showTime
                  style={{ width: "100%" }}
                  allowClear
                  ranges={{
                    "Last 24h": [dayjs().subtract(1, "day"), dayjs()],
                    "Last 7 days": [dayjs().subtract(7, "day"), dayjs()],
                  }}
                />
              </Form.Item>
            </Col>
            <Col xs={24} md={12} lg={4}>
              <Form.Item label="User ID" name="user_id">
                <Input placeholder="e.g. 42" allowClear />
              </Form.Item>
            </Col>
          </Row>
          <Collapse bordered={false} ghost style={{ marginBottom: 16 }}>
            <Panel
              key="advanced"
              header="Advanced filters"
              extra={<Text type="secondary">Employee, department, resource, action, and keyword filters</Text>}
            >
              <Alert
                type="info"
                showIcon
                message="Advanced filters are optional"
                description="Use the date range and user ID fields first. Expand this section when you need to narrow logs by employee, department, resource, action, or keyword."
                style={{ marginBottom: 16 }}
              />
              <Row gutter={16}>
                <Col xs={24} md={12} lg={6}>
                  <Form.Item label="Employee" name="employee_id">
                    <EmployeeDropdown
                      value={selectedEmployeeId}
                      onChange={(val) => handleEmployeeFilterChange(val as number)}
                      placeholder="Any employee"
                      allowClear
                    />
                  </Form.Item>
                </Col>
                <Col xs={24} md={12} lg={6}>
                  <Form.Item label="Department" name="department_id">
                    <DepartmentDropdown placeholder="Any department" allowClear />
                  </Form.Item>
                </Col>
                <Col xs={24} md={12} lg={4}>
                  <Form.Item label="Resource" name="resource_type">
                    <Select allowClear options={RESOURCE_OPTIONS} placeholder="Any" />
                  </Form.Item>
                </Col>
                <Col xs={24} md={12} lg={4}>
                  <Form.Item label="Action" name="action">
                    <Select allowClear options={ACTION_OPTIONS} placeholder="Any" />
                  </Form.Item>
                </Col>
                <Col xs={24} md={12} lg={4}>
                  <Form.Item label="Keyword" name="keyword">
                    <Input allowClear placeholder="resource, IP..." />
                  </Form.Item>
                </Col>
              </Row>
            </Panel>
          </Collapse>
          <Space wrap>
            <Button type="primary" htmlType="submit" icon={<FilterOutlined />} loading={loading}>
              Apply Filters
            </Button>
            <Button onClick={handleReset}>Reset</Button>
            <Button icon={<ReloadOutlined />} onClick={() => refresh(filters)}>
              Refresh
            </Button>
          </Space>
        </Form>
      </Card>

      {error ? (
        <Alert type="error" message="Failed to load logs" description={error} />
      ) : null}

      {/* Audit Records Table */}
      <Card title="Audit Records">
        <Tabs
          activeKey={actorTypeTab}
          items={ACTOR_TYPE_TABS}
          onChange={handleActorTypeTabChange}
          style={{ marginTop: -8 }}
        />
        <Table
          rowKey="id"
          loading={loading}
          columns={columns}
          dataSource={logs}
          pagination={{
            current: pagination.page,
            pageSize: pagination.pageSize,
            total: pagination.total,
            onChange: handlePageChange,
            showSizeChanger: true,
          }}
        />
      </Card>

      {/* Detail Drawer */}
      <Drawer
        title="Audit Log Details"
        placement="right"
        onClose={() => setDrawerVisible(false)}
        open={drawerVisible}
        width={700}
      >
        <Spin spinning={drawerLoading}>
          {selectedLog && (
            <Space direction="vertical" size={16} style={{ width: "100%" }}>
              <Descriptions bordered column={1} size="small">
                <Descriptions.Item label="ID">{selectedLog.id}</Descriptions.Item>
                <Descriptions.Item label="User ID">
                  {selectedLog.user_id ? `User #${selectedLog.user_id}` : "System"}
                </Descriptions.Item>
                <Descriptions.Item label="Action">{selectedLog.action}</Descriptions.Item>
                <Descriptions.Item label="Resource Type">{selectedLog.resource_type}</Descriptions.Item>
                <Descriptions.Item label="Resource ID">{selectedLog.resource_id || "-"}</Descriptions.Item>
                <Descriptions.Item label="IP Address">{selectedLog.ip_address || "-"}</Descriptions.Item>
                <Descriptions.Item label="User Agent (full)">
                  <Text style={{ wordBreak: "break-word" }}>{selectedLog.user_agent || "-"}</Text>
                </Descriptions.Item>
                <Descriptions.Item label="Timestamp (UTC)">
                  {dayjs(selectedLog.created_at).format("YYYY-MM-DD HH:mm:ss")}
                </Descriptions.Item>
              </Descriptions>

              {selectedLog.metadata && Object.keys(selectedLog.metadata).length > 0 && (
                <>
                  <Divider style={{ margin: "16px 0" }} />
                  <div>
                    <Text strong>Metadata</Text>
                    <CodeBlock value={selectedLog.metadata} empty="No metadata" />
                  </div>
                </>
              )}

              {selectedLog.before_state && Object.keys(selectedLog.before_state).length > 0 && (
                <>
                  <Divider style={{ margin: "16px 0" }} />
                  <div>
                    <Text strong>Before State</Text>
                    <CodeBlock value={selectedLog.before_state} empty="No before state" />
                  </div>
                </>
              )}

              {selectedLog.after_state && Object.keys(selectedLog.after_state).length > 0 && (
                <>
                  <Divider style={{ margin: "16px 0" }} />
                  <div>
                    <Text strong>After State</Text>
                    <CodeBlock value={selectedLog.after_state} empty="No after state" />
                  </div>
                </>
              )}
            </Space>
          )}
        </Spin>
      </Drawer>
    </Space>
  );
}

function CodeBlock({ value, empty }: { value?: Record<string, unknown>; empty: string }) {
  if (!value || Object.keys(value).length === 0) {
    return <Text type="secondary">{empty}</Text>;
  }
  return (
    <pre
      style={{
        background: "#0f172a",
        color: "#e2e8f0",
        padding: 12,
        borderRadius: 8,
        maxHeight: 300,
        overflow: "auto",
      }}
    >
      {JSON.stringify(value, null, 2)}
    </pre>
  );
}
