import React, { useCallback, useRef, useState } from 'react';
import {
  Badge,
  Box,
  Button,
  Icon,
  IconButton,
  Icons,
  Input,
  Scroll,
  Text,
  color,
  config,
} from 'folds';
import { EventTimeline, MatrixEvent, Room } from 'matrix-js-sdk';
import { Page, PageContent, PageHeader } from '../../components/page';
import { useMatrixClient } from '../../hooks/useMatrixClient';
import { SequenceCard } from '../../components/sequence-card';
import { SequenceCardStyle } from '../common-settings/styles.css';

// ── Policy event types ────────────────────────────────────────────────────────

const POLICY_USER_EVENT = 'm.policy.rule.user';
const POLICY_ROOM_EVENT = 'm.policy.rule.room';
const POLICY_SERVER_EVENT = 'm.policy.rule.server';

type PolicyRuleContent = {
  entity?: string;
  reason?: string;
  recommendation?: string;
};

type PolicyEntry = {
  entity: string;
  reason: string;
  recommendation: string;
  stateKey: string;
};

type PolicyTab = 'users' | 'rooms' | 'servers';

// ── Helpers ───────────────────────────────────────────────────────────────────

function isGlob(entity: string): boolean {
  return entity.includes('*') || entity.includes('?');
}

function recommendationLabel(rec: string): string {
  // `m.ban` is the stable value; `org.matrix.mjolnir.ban` is the legacy
  // (pre-stabilization) recommendation still emitted by older bots.
  if (rec === 'm.ban' || rec === 'org.matrix.mjolnir.ban') return 'Ban';
  return rec;
}

/**
 * Fetch all state events of a given type from a room's live forward state.
 * Uses the raw matrix-js-sdk `getStateEvents` API which accepts any string type.
 */
function getRoomPolicyEvents(room: Room, eventType: string): MatrixEvent[] {
  const state = room.getLiveTimeline().getState(EventTimeline.FORWARDS);
  if (!state) return [];
  return state.getStateEvents(eventType);
}

function extractPolicyEntries(events: MatrixEvent[]): PolicyEntry[] {
  return events
    .map((e) => {
      const content = e.getContent<PolicyRuleContent>();
      return {
        entity: content.entity ?? '',
        reason: content.reason ?? '',
        recommendation: content.recommendation ?? '',
        stateKey: e.getStateKey() ?? '',
      };
    })
    .filter((entry) => entry.entity !== '');
}

// ── Entry row ─────────────────────────────────────────────────────────────────

function PolicyEntryRow({ entry }: { entry: PolicyEntry }) {
  const glob = isGlob(entry.entity);
  return (
    <Box
      direction="Column"
      gap="100"
      style={{
        padding: `${config.space.S200} ${config.space.S300}`,
        borderBottom: `1px solid ${color.Surface.ContainerLine}`,
      }}
    >
      <Box gap="200" alignItems="Center" wrap="Wrap">
        <Text
          size="T300"
          style={{
            fontFamily: 'monospace',
            color: glob ? color.Warning.Main : undefined,
            wordBreak: 'break-all',
          }}
        >
          {entry.entity}
        </Text>
        {glob && (
          <Badge variant="Warning" fill="Soft" radii="Pill">
            <Text size="T200">glob</Text>
          </Badge>
        )}
        {entry.recommendation && (
          <Badge variant="Critical" fill="Soft" radii="Pill">
            <Text size="T200">{recommendationLabel(entry.recommendation)}</Text>
          </Badge>
        )}
      </Box>
      {entry.reason && (
        <Text size="T200" priority="300" style={{ wordBreak: 'break-word' }}>
          {entry.reason}
        </Text>
      )}
    </Box>
  );
}

// ── Tab button ────────────────────────────────────────────────────────────────

function TabButton({
  label,
  count,
  active,
  onClick,
}: {
  label: string;
  count: number;
  active: boolean;
  onClick: () => void;
}) {
  return (
    <Button
      onClick={onClick}
      variant={active ? 'Primary' : 'Secondary'}
      fill={active ? 'Solid' : 'Soft'}
      size="300"
      radii="300"
    >
      <Text size="B300">
        {label} ({count})
      </Text>
    </Button>
  );
}

// ── Main component ────────────────────────────────────────────────────────────

type PolicyListViewerProps = {
  requestClose: () => void;
};

export function PolicyListViewer({ requestClose }: PolicyListViewerProps) {
  const mx = useMatrixClient();
  const inputRef = useRef<HTMLInputElement>(null);

  const [roomIdInput, setRoomIdInput] = useState('');
  const [activeTab, setActiveTab] = useState<PolicyTab>('users');
  const [error, setError] = useState<string | undefined>();

  const [userEntries, setUserEntries] = useState<PolicyEntry[]>([]);
  const [roomEntries, setRoomEntries] = useState<PolicyEntry[]>([]);
  const [serverEntries, setServerEntries] = useState<PolicyEntry[]>([]);
  const [loadedRoomId, setLoadedRoomId] = useState<string | undefined>();

  const handleLoad = useCallback(() => {
    const rawInput = (inputRef.current?.value ?? roomIdInput).trim();
    if (!rawInput) {
      setError('Please enter a room ID or alias.');
      return;
    }

    // Resolve alias to room ID using local cache
    let roomId = rawInput;
    if (rawInput.startsWith('#')) {
      const cachedId = mx.getRooms().find((r) => {
        const aliases = r.getAltAliases();
        const canonical = r.getCanonicalAlias();
        return aliases.includes(rawInput) || canonical === rawInput;
      })?.roomId;

      if (cachedId) {
        roomId = cachedId;
      } else {
        setError(`Cannot resolve alias "${rawInput}". Make sure you have joined that room.`);
        return;
      }
    }

    const room = mx.getRoom(roomId);
    if (!room) {
      setError(`Not joined to room "${roomId}". Join the policy list room first.`);
      setUserEntries([]);
      setRoomEntries([]);
      setServerEntries([]);
      setLoadedRoomId(undefined);
      return;
    }

    setUserEntries(extractPolicyEntries(getRoomPolicyEvents(room, POLICY_USER_EVENT)));
    setRoomEntries(extractPolicyEntries(getRoomPolicyEvents(room, POLICY_ROOM_EVENT)));
    setServerEntries(extractPolicyEntries(getRoomPolicyEvents(room, POLICY_SERVER_EVENT)));
    setLoadedRoomId(roomId);
    setError(undefined);
  }, [mx, roomIdInput]);

  const activeEntries =
    activeTab === 'users' ? userEntries : activeTab === 'rooms' ? roomEntries : serverEntries;

  return (
    <Page>
      <PageHeader outlined={false}>
        <Box grow="Yes" gap="200">
          <Box grow="Yes" alignItems="Center" gap="200">
            <Text as="h2" size="H3" truncate>
              Policy Lists
            </Text>
          </Box>
          <Box shrink="No">
            <IconButton onClick={requestClose} variant="Surface" aria-label="Close">
              <Icon src={Icons.Cross} />
            </IconButton>
          </Box>
        </Box>
      </PageHeader>
      <Box grow="Yes">
        <Scroll hideTrack visibility="Hover">
          <PageContent>
            <Box direction="Column" gap="700">
              {/* Description */}
              <Box direction="Column" gap="100">
                <Text size="L400">About</Text>
                <SequenceCard
                  className={SequenceCardStyle}
                  variant="SurfaceVariant"
                  direction="Column"
                  gap="200"
                >
                  <Text size="T300">
                    Policy lists are Matrix rooms containing ban rules managed by moderation bots
                    (e.g. Draupnir). Enter a policy list room ID below to inspect its current rules.
                    This is a read-only viewer — rule enforcement is handled by your moderation bot.
                  </Text>
                </SequenceCard>
              </Box>

              {/* Room ID input */}
              <Box direction="Column" gap="100">
                <Text size="L400">Policy List Room</Text>
                <SequenceCard
                  className={SequenceCardStyle}
                  variant="SurfaceVariant"
                  direction="Column"
                  gap="300"
                >
                  <Box gap="200" alignItems="Center">
                    <Input
                      ref={inputRef}
                      value={roomIdInput}
                      onChange={(e) => setRoomIdInput(e.target.value)}
                      onKeyDown={(e) => {
                        if (e.key === 'Enter') handleLoad();
                      }}
                      placeholder="!roomId:server or #alias:server"
                      variant={error ? 'Critical' : 'Secondary'}
                      size="400"
                      radii="300"
                      style={{ flexGrow: 1 }}
                    />
                    <Button
                      onClick={handleLoad}
                      variant="Primary"
                      fill="Solid"
                      size="300"
                      radii="300"
                      before={<Icon src={Icons.Search} size="100" />}
                    >
                      <Text size="B300">Load</Text>
                    </Button>
                  </Box>
                  {error && (
                    <Text size="T200" style={{ color: color.Critical.Main }}>
                      {error}
                    </Text>
                  )}
                  {loadedRoomId && (
                    <Text size="T200" priority="300">
                      Showing rules from:{' '}
                      <span style={{ fontFamily: 'monospace' }}>{loadedRoomId}</span>
                    </Text>
                  )}
                </SequenceCard>
              </Box>

              {/* Rules viewer */}
              {loadedRoomId && (
                <Box direction="Column" gap="100">
                  <Text size="L400">Rules</Text>
                  <SequenceCard
                    className={SequenceCardStyle}
                    variant="SurfaceVariant"
                    direction="Column"
                    gap="300"
                  >
                    {/* Tabs */}
                    <Box gap="200" wrap="Wrap">
                      <TabButton
                        label="Users"
                        count={userEntries.length}
                        active={activeTab === 'users'}
                        onClick={() => setActiveTab('users')}
                      />
                      <TabButton
                        label="Rooms"
                        count={roomEntries.length}
                        active={activeTab === 'rooms'}
                        onClick={() => setActiveTab('rooms')}
                      />
                      <TabButton
                        label="Servers"
                        count={serverEntries.length}
                        active={activeTab === 'servers'}
                        onClick={() => setActiveTab('servers')}
                      />
                    </Box>

                    {/* Entry list */}
                    <Box
                      direction="Column"
                      style={{
                        border: `1px solid ${color.Surface.ContainerLine}`,
                        borderRadius: config.radii.R300,
                        overflow: 'hidden',
                      }}
                    >
                      {activeEntries.length === 0 ? (
                        <Box
                          alignItems="Center"
                          justifyContent="Center"
                          style={{ padding: config.space.S500 }}
                        >
                          <Text size="T300" priority="300">
                            No{' '}
                            {activeTab === 'users'
                              ? 'user'
                              : activeTab === 'rooms'
                                ? 'room'
                                : 'server'}{' '}
                            ban rules found.
                          </Text>
                        </Box>
                      ) : (
                        activeEntries.map((entry) => (
                          <PolicyEntryRow key={entry.stateKey || entry.entity} entry={entry} />
                        ))
                      )}
                    </Box>
                  </SequenceCard>
                </Box>
              )}
            </Box>
          </PageContent>
        </Scroll>
      </Box>
    </Page>
  );
}
