import { useState } from 'react';
import { Link as RouterLink } from 'react-router';

import DataObjectIcon from '@mui/icons-material/DataObject';
import InfoIcon from '@mui/icons-material/InfoOutlined';
import MoreVertIcon from '@mui/icons-material/MoreVert';
import PersonIcon from '@mui/icons-material/Person';
import StarIcon from '@mui/icons-material/Star';
import StarBorderIcon from '@mui/icons-material/StarBorder';
import SwapVertIcon from '@mui/icons-material/SwapVert';
import WorkspacesIcon from '@mui/icons-material/Workspaces';
import {
  Box,
  Divider,
  IconButton,
  Link,
  linkClasses,
  ListItemText,
  Menu,
  MenuItem,
  svgIconClasses,
  Table,
  TableBody,
  TableCell,
  tableCellClasses,
  TableHead,
  TableRow,
  TableSortLabel,
  type Theme,
  Tooltip,
  Typography
} from '@mui/material';

import { darkBackground, gray, orange } from '../../../themes/common';
import { formatProfileTime } from '../../../utils/time';
import type { Group, GroupType, SortState } from '../types';
import { getUserName } from '../utils/format';
import { computeDropPriority } from '../utils/priority';

// Horizontal-only borders; the app theme defaults <Table> to a full grid with
// 700-weight head cells.
const horizontalTableSx = {
  border: 'none',
  width: '100%',
  maxWidth: 1050,
  [`& .${tableCellClasses.root}`]: { borderRight: 'none' },
  [`& .${tableCellClasses.head}`]: { fontWeight: 500 },
  [`& tbody tr:last-child .${tableCellClasses.root}`]: { borderBottom: 'none' }
} as const;

const iconBadgeSx = (theme: Theme) => ({
  alignItems: 'center',
  backgroundColor: theme.palette.mode === 'dark' ? darkBackground[50] : gray[200],
  borderRadius: '50%',
  color: 'text.muted',
  display: 'inline-flex',
  flexShrink: 0,
  height: 20,
  justifyContent: 'center',
  width: 20,
  [`& .${svgIconClasses.root}`]: { fontSize: 14 }
});

interface GroupsTableProps {
  groups: Group[];
  onChangePriority: (id: string | number, priority: number) => void;
  onDuplicate: (group: Group) => void;
  onRemove: (group: Group) => void;
  onSort: (column: string) => void;
  onToggleFavorite: (group: Group, favorite: boolean) => void;
  sort: SortState;
  total: number;
  type: GroupType;
}

const isShared = (type?: GroupType) => type === 'shared';

const groupPath = (group: Group, listType: GroupType) => {
  const type = isShared(group.type) || isShared(listType) ? 'shared' : 'personal';
  return `/${type}/${group.id}`;
};

interface SortHeaderProps {
  align?: 'left' | 'right';
  children: React.ReactNode;
  column: string;
  onSort: (column: string) => void;
  sort: SortState;
  width?: number | string;
}

const SortHeader = ({ align = 'left', children, column, onSort, sort, width }: SortHeaderProps) => (
  <TableCell align={align} sx={width ? { width, whiteSpace: 'nowrap' } : undefined} sortDirection={sort.column === column ? (sort.descending ? 'desc' : 'asc') : false}>
    <TableSortLabel active={sort.column === column} direction={sort.column === column && sort.descending ? 'desc' : 'asc'} onClick={() => onSort(column)}>
      {children}
    </TableSortLabel>
  </TableCell>
);

export const GroupsTable = ({ type, groups, sort, total, onSort, onToggleFavorite, onDuplicate, onRemove, onChangePriority }: GroupsTableProps) => {
  const shared = isShared(type);
  const [dragIndex, setDragIndex] = useState<number | null>(null);

  const handleDrop = (toIndex: number) => {
    if (dragIndex === null) return;
    const priority = computeDropPriority(groups, dragIndex, toIndex);
    const moved = groups[dragIndex];
    setDragIndex(null);
    if (priority !== null && moved) onChangePriority(moved.id, priority);
  };

  return (
    <Table sx={horizontalTableSx}>
      <TableHead>
        <TableRow>
          {shared && (
            <TableCell sx={{ width: 56 }} sortDirection={sort.column === 'priority' ? (sort.descending ? 'desc' : 'asc') : false}>
              <Tooltip title="Priority number used when merging data for hosts in multiple groups. Higher priority number is preferred.">
                <IconButton size="small" aria-label="Sort by priority" sx={{ p: 0 }} onClick={() => onSort('priority')}>
                  <SwapVertIcon fontSize="small" />
                </IconButton>
              </Tooltip>
            </TableCell>
          )}
          <SortHeader column="name" sort={sort} onSort={onSort}>
            <Box component="span" sx={{ display: 'inline-flex', alignItems: 'center', gap: 1 }}>
              <Tooltip title="Shared groups can be added to My groups by clicking the star next to the group name">
                <InfoIcon fontSize="small" color="action" />
              </Tooltip>
              Group name
            </Box>
          </SortHeader>
          <TableCell>Number of hosts</TableCell>
          <SortHeader column="creation_time" sort={sort} onSort={onSort}>
            Created at
          </SortHeader>
          <SortHeader column={shared ? 'creator' : 'owner'} sort={sort} onSort={onSort}>
            Created by
          </SortHeader>
          <TableCell align="right">{shared ? '' : 'Actions'}</TableCell>
        </TableRow>
      </TableHead>
      <TableBody>
        {groups.map((group, index) => (
          <GroupRow
            key={group.id}
            group={group}
            index={index}
            listType={type}
            shared={shared}
            total={total}
            onDragStart={setDragIndex}
            onDrop={handleDrop}
            onToggleFavorite={onToggleFavorite}
            onDuplicate={onDuplicate}
            onRemove={onRemove}
            onChangePriority={onChangePriority}
          />
        ))}
      </TableBody>
    </Table>
  );
};

interface GroupRowProps {
  group: Group;
  index: number;
  listType: GroupType;
  onChangePriority: (id: string | number, priority: number) => void;
  onDragStart: (index: number) => void;
  onDrop: (index: number) => void;
  onDuplicate: (group: Group) => void;
  onRemove: (group: Group) => void;
  onToggleFavorite: (group: Group, favorite: boolean) => void;
  shared: boolean;
  total: number;
}

const FavoriteButton = ({ group, onToggle }: { group: Group; onToggle: (group: Group, favorite: boolean) => void }) => {
  const label = group.is_favorite ? 'Remove from favorites' : 'Add to favorites';
  const iconColor = group.is_favorite ? orange[700] : 'action.disabled';
  return (
    <IconButton
      size="small"
      aria-label={label}
      title={label}
      sx={{ p: 0, color: iconColor }}
      onClick={() => onToggle(group, !group.is_favorite)}
    >
      {group.is_favorite ? <StarIcon fontSize="small" /> : <StarBorderIcon fontSize="small" />}
    </IconButton>
  );
};

const GroupRow = ({ group, index, listType, shared, total, onChangePriority, onDragStart, onDrop, onDuplicate, onRemove, onToggleFavorite }: GroupRowProps) => {
  const showFavorite = isShared(group.type) || shared;
  const dragProps = shared
    ? {
        draggable: true,
        onDragStart: () => onDragStart(index),
        onDragOver: (event: React.DragEvent) => event.preventDefault(),
        onDrop: () => onDrop(index),
        title: 'Drag to reorder: move down to increase priority.'
      }
    : {};

  return (
    <TableRow hover {...dragProps}>
      {shared && <TableCell sx={{ width: 56 }}>{group.priority}</TableCell>}
      <TableCell>
        <Box component="span" sx={{ alignItems: 'center', display: 'inline-flex', gap: 1 }}>
          {/* No favorite star on personal groups; reserve the slot so names stay
              left-aligned with starred rows. */}
          {showFavorite ? <FavoriteButton group={group} onToggle={onToggleFavorite} /> : <Box component="span" sx={{ width: 20 }} />}
          <Link component={RouterLink} to={groupPath(group, listType)}>
            {group.name}
          </Link>
          <GroupIcon group={group} />
        </Box>
      </TableCell>
      <TableCell>{group.hosts_number}</TableCell>
      <TableCell>{formatProfileTime(group.creation_time)}</TableCell>
      <TableCell>
        <CreatedBy group={group} />
      </TableCell>
      <TableCell align="right">
        {shared ? (
          <SharedActionsMenu group={group} total={total} onRemove={onRemove} onDuplicate={onDuplicate} onChangePriority={onChangePriority} />
        ) : (
          <PersonalActions group={group} type={listType} onDuplicate={onDuplicate} onRemove={onRemove} />
        )}
      </TableCell>
    </TableRow>
  );
};

// meta_data.source values the backend uses to mark non-user creators.
const CFE_TEAM_SOURCE = 'from CFEngine team';
const BUILD_MODULE_SOURCE = 'build module';

// System-created groups (CFEngine team / build module) show an avatar + tooltip
// instead of the raw username. Avatar styling comes from the global stylesheet.
const CreatedBy = ({ group }: { group: Group }) => {
  const source = group.meta_data?.source;
  if (source === CFE_TEAM_SOURCE) {
    return (
      <Tooltip title="This item was made by the CFEngine development team.">
        <span className="label-icon agent_icon" />
      </Tooltip>
    );
  }
  if (source === BUILD_MODULE_SOURCE) {
    return (
      <Tooltip title="This item was imported using a module from CFEngine Build.">
        <span className="label-icon build_icon" />
      </Tooltip>
    );
  }
  return <>{getUserName(group)}</>;
};

const GroupIcon = ({ group }: { group: Group }) => {
  const { icon, title } = group.has_data
    ? { icon: <DataObjectIcon />, title: 'Shared group with data' }
    : isShared(group.type)
      ? { icon: <WorkspacesIcon />, title: 'Shared group (no data)' }
      : { icon: <PersonIcon />, title: 'Personal group' };
  return (
    <Tooltip title={title}>
      <Box sx={iconBadgeSx}>{icon}</Box>
    </Tooltip>
  );
};

const personalActionsSx = {
  display: 'inline-flex',
  gap: 1.5,
  whiteSpace: 'nowrap',
  [`& .${linkClasses.root}`]: {
    color: 'link.primary',
    '&:hover': { textDecoration: 'underline' }
  }
} as const;

const PersonalActions = ({ group, type, onDuplicate, onRemove }: { group: Group; onDuplicate: (g: Group) => void; onRemove: (g: Group) => void; type: GroupType }) => (
  <Box component="span" sx={personalActionsSx}>
    <Link component={RouterLink} to={groupPath(group, type)}>
      Edit
    </Link>
    <Link component="button" type="button" onClick={() => onDuplicate(group)}>
      Duplicate
    </Link>
    <Link component="button" type="button" onClick={() => onRemove(group)}>
      Remove
    </Link>
  </Box>
);

const SharedActionsMenu = ({
  group,
  total,
  onRemove,
  onDuplicate,
  onChangePriority
}: {
  group: Group;
  onChangePriority: (id: string | number, priority: number) => void;
  onDuplicate: (g: Group) => void;
  onRemove: (g: Group) => void;
  total: number;
}) => {
  const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
  const close = () => setAnchorEl(null);
  const priority = group.priority ?? 1;
  const isTop = priority === 1;
  const isBottom = priority === total;

  const run = (action: () => void) => () => {
    action();
    close();
  };

  return (
    <>
      <IconButton size="small" aria-label="Group actions" onClick={event => setAnchorEl(event.currentTarget)}>
        <MoreVertIcon fontSize="small" />
      </IconButton>
      <Menu anchorEl={anchorEl} open={Boolean(anchorEl)} onClose={close}>
        <MenuItem component={RouterLink} to={`/shared/${group.id}`} onClick={close}>
          Edit
        </MenuItem>
        <MenuItem onClick={run(() => onRemove(group))}>Remove</MenuItem>
        <MenuItem onClick={run(() => onDuplicate(group))}>Duplicate</MenuItem>
        <Divider />
        <MenuItem disabled dense>
          <Typography variant="subtitle2">Priority</Typography>
        </MenuItem>
        {/* Backend priority sentinels: 1 = top (lowest), -1 = bottom (highest). */}
        <MenuItem disabled={isTop} onClick={run(() => onChangePriority(group.id, 1))}>
          <ListItemText>Move to top (lowest priority)</ListItemText>
        </MenuItem>
        <MenuItem disabled={isTop} onClick={run(() => onChangePriority(group.id, priority - 1))}>
          <ListItemText>Move one up</ListItemText>
        </MenuItem>
        <MenuItem disabled={isBottom} onClick={run(() => onChangePriority(group.id, -1))}>
          <ListItemText>Move to bottom (highest priority)</ListItemText>
        </MenuItem>
        <MenuItem disabled={isBottom} onClick={run(() => onChangePriority(group.id, priority + 1))}>
          <ListItemText>Move one down</ListItemText>
        </MenuItem>
      </Menu>
    </>
  );
};
