import { useMemo, useState } from 'react'
import { m, mKey } from '@/i18n/messages'
import { useLocale } from '@/i18n/config'
import { asI18n } from '@pikku/react'
import {
  Badge,
  Box,
  Button,
  Group,
  Paper,
  Select,
  SimpleGrid,
  Stack,
  Table,
  Text,
} from '@pikku/mantine/core'

type Room = {
  roomId: string
  number: number
  beds: number
  roomType: string
  building: string
  floor: string
  wheelchair: number
  groundFloor: number
  quiet: number
  sharedBath: number
  dogsAllowed: number
  doubleBed_140: number
  allergyFriendly: number
  occupiedByOtherBooking: boolean
  assignedParticipants: { participantId: string; name: string }[]
}

type Participant = { participantId: string; name: string; roomId: string | null }

const PALETTE = {
  empty: '#FBF8FA',
  emptyBorder: '#E5DDE3',
  filled: '#E9D4E2',
  filledBorder: '#88557F',
  partial: '#F0E4EC',
  full: '#88557F',
  fullText: '#FFFFFF',
  occupiedOther: '#EDEDED',
  occupiedOtherText: '#9B9499',
  hover: '#FFCE00',
}

const initials = (name: string) =>
  name
    .split(/\s+/)
    .filter(Boolean)
    .slice(0, 2)
    .map((p) => p[0]?.toUpperCase() ?? '')
    .join('')

// Stable, soft per-participant tint so each guest reads as a distinct chip
// in the floor plan without leaving the brand palette.
const TINTS = [
  '#88557F',
  '#A05C8E',
  '#BC7AA6',
  '#D3A7C4',
  '#FFBC7D',
  '#F37E15',
  '#FFCE00',
  '#806600',
  '#4E3149',
  '#583651',
]
const tintFor = (id: string) => {
  let h = 0
  for (let i = 0; i < id.length; i++) h = (h * 31 + id.charCodeAt(i)) | 0
  return TINTS[Math.abs(h) % TINTS.length]
}

type Group = { building: string; floor: string; rooms: Room[] }

function groupRooms(rooms: Room[]): Group[] {
  const map = new Map<string, Room[]>()
  for (const r of rooms) {
    const key = `${r.building}::${r.floor}`
    if (!map.has(key)) map.set(key, [])
    map.get(key)!.push(r)
  }
  const order = ['gaestehaus::eg', 'gaestehaus::og', 'haupthaus::eg', 'haupthaus::og']
  return Array.from(map.entries())
    .map(([k, rs]) => {
      const [building, floor] = k.split('::')
      return { building, floor, rooms: rs.sort((a, b) => a.number - b.number) }
    })
    .sort(
      (a, b) =>
        order.indexOf(`${a.building}::${a.floor}`) - order.indexOf(`${b.building}::${b.floor}`),
    )
}

function buildingLabel(building: string, floor: string) {
  const b = mKey(`common.pages.adminBooking.rooms.buildings.${building}` as any)
  const f = mKey(`common.pages.adminBooking.rooms.floors.${floor}` as any)
  return `${b} · ${f}`
}

export function RoomsTab({
  rooms,
  participants,
  bookingId,
  assign,
  unassign,
}: {
  rooms: Room[]
  participants: Participant[]
  bookingId: string
  assign: (args: { bookingId: string; participantId: string; roomId: string }) => void
  unassign: (args: { participantId: string }) => void
}) {
  useLocale()
  const [hovered, setHovered] = useState<string | null>(null)
  const groups = useMemo(() => groupRooms(rooms), [rooms])
  const unassigned = participants.filter((p) => !p.roomId)

  return (
    <SimpleGrid cols={{ base: 1, lg: 2 }} spacing="lg" data-testid="rooms-tab">
      {/* Left pane: room list ----------------------------------------- */}
      <Paper withBorder radius="md" p={0}>
        <Table highlightOnHover>
            <Table.Thead>
              <Table.Tr>
                <Table.Th style={{ width: 64 }}>{m.common_pages_admin_booking_rooms_cols_room()}</Table.Th>
                <Table.Th>{m.common_pages_admin_booking_rooms_cols_guests()}</Table.Th>
                <Table.Th style={{ width: 200 }}>{m.common_pages_admin_booking_rooms_cols_assign()}</Table.Th>
              </Table.Tr>
            </Table.Thead>
            <Table.Tbody>
              {groups.map((g) => (
                <RoomGroupRows
                  key={`${g.building}-${g.floor}`}
                  group={g}
                  hovered={hovered}
                  onHover={setHovered}
                  unassigned={unassigned}
                  assign={assign}
                  unassign={unassign}
                  bookingId={bookingId}
                />
              ))}
            </Table.Tbody>
          </Table>
      </Paper>

      {/* Right pane: SVG floorplan -------------------------------------- */}
      <Stack gap="md">
        {groups.map((g) => (
          <Paper key={`${g.building}-${g.floor}`} withBorder radius="md" p="md">
            <Stack gap="sm">
              <Text size="xs" tt="uppercase" c="dimmed" fw={600} style={{ letterSpacing: '0.08em' }}>
                {asI18n(`${buildingLabel(g.building, g.floor)}`)}
              </Text>
              <FloorPlan
                rooms={g.rooms}
                hovered={hovered}
                onHover={setHovered}
              />
            </Stack>
          </Paper>
        ))}
      </Stack>
    </SimpleGrid>
  )
}

function RoomGroupRows({
  group,
  hovered,
  onHover,
  unassigned,
  assign,
  unassign,
  bookingId,
}: {
  group: Group
  hovered: string | null
  onHover: (id: string | null) => void
  unassigned: Participant[]
  assign: (args: { bookingId: string; participantId: string; roomId: string }) => void
  unassign: (args: { participantId: string }) => void
  bookingId: string
}) {
  useLocale()
  return (
    <>
      <Table.Tr>
        <Table.Td colSpan={3} style={{ background: '#FBF8FA' }}>
          <Text size="xs" tt="uppercase" c="dimmed" fw={600} style={{ letterSpacing: '0.08em' }}>
            {asI18n(`${buildingLabel(group.building, group.floor)}`)}
          </Text>
        </Table.Td>
      </Table.Tr>
      {group.rooms.map((r) => (
        <Table.Tr
          key={r.roomId}
          onMouseEnter={() => onHover(r.roomId)}
          onMouseLeave={() => onHover(null)}
          style={{
            background: hovered === r.roomId ? 'rgba(255, 206, 0, 0.12)' : undefined,
            cursor: 'default',
          }}
        >
          <Table.Td>
            <Group gap={6} wrap="nowrap">
              <Text fw={700}>{r.number}</Text>
              <Badge size="xs" variant="light" color="gray">
                {asI18n(`${r.roomType}`)}
              </Badge>
            </Group>
            <Text size="xs" c="dimmed">{asI18n(`${r.beds} ${m.common_pages_admin_booking_rooms_beds()}`)}</Text>
          </Table.Td>
          <Table.Td>
            {r.occupiedByOtherBooking ? (
              <Text size="xs" c="dimmed" fs="italic">
                {m.common_pages_admin_booking_rooms_occupied_other()}
              </Text>
            ) : r.assignedParticipants.length === 0 ? (
              <Text size="xs" c="dimmed">{asI18n('—')}</Text>
            ) : (
              <Stack gap={4}>
                {r.assignedParticipants.map((p) => (
                  <Group key={p.participantId} gap={6} wrap="nowrap" justify="space-between">
                    <Group gap={6} wrap="nowrap">
                      <Box
                        style={{
                          width: 18,
                          height: 18,
                          borderRadius: 9,
                          background: tintFor(p.participantId),
                          color: '#fff',
                          fontSize: 9,
                          fontWeight: 700,
                          display: 'inline-flex',
                          alignItems: 'center',
                          justifyContent: 'center',
                          flexShrink: 0,
                        }}
                      >
                        {initials(p.name)}
                      </Box>
                      <Text size="sm">{asI18n(`${p.name}`)}</Text>
                    </Group>
                    <Button
                      size="compact-xs"
                      variant="subtle"
                      color="gray"
                      onClick={() => unassign({ participantId: p.participantId })}
                    >
                      {m.common_pages_admin_booking_rooms_unassign()}
                    </Button>
                  </Group>
                ))}
              </Stack>
            )}
          </Table.Td>
          <Table.Td>
            {!r.occupiedByOtherBooking && unassigned.length > 0 && (
              <Select
                size="xs"
                data-testid={`assign-room-${r.roomId}`}
                placeholder={m.common_pages_admin_booking_rooms_assign_to_participant()}
                data={unassigned.map((p) => ({ value: p.participantId, label: p.name }))}
                value={null}
                onChange={(v) =>
                  v && assign({ bookingId, participantId: v, roomId: r.roomId })
                }
                clearable={false}
              />
            )}
          </Table.Td>
        </Table.Tr>
      ))}
    </>
  )
}

// ─── SVG floor plan ─────────────────────────────────────────────────────
// Schematic only — not architecturally accurate. Rooms are laid out as a
// grid with their real number; layout is responsive to the room count per
// floor section.

function FloorPlan({
  rooms,
  hovered,
  onHover,
}: {
  rooms: Room[]
  hovered: string | null
  onHover: (id: string | null) => void
}) {
  const cols = Math.min(6, Math.max(2, Math.ceil(Math.sqrt(rooms.length * 1.6))))
  const rows = Math.ceil(rooms.length / cols)
  const W = 480
  const cellGap = 6
  const padX = 12
  const padY = 12
  const cellW = (W - padX * 2 - cellGap * (cols - 1)) / cols
  const cellH = 84
  const H = padY * 2 + rows * cellH + (rows - 1) * cellGap

  return (
    <Box style={{ width: '100%' }}>
      <svg
        viewBox={`0 0 ${W} ${H}`}
        width="100%"
        style={{ display: 'block', borderRadius: 8 }}
      >
        <rect x="0" y="0" width={W} height={H} fill="#ffffff" stroke="#E5DDE3" rx="8" />
        {rooms.map((r, i) => {
          const c = i % cols
          const row = Math.floor(i / cols)
          const x = padX + c * (cellW + cellGap)
          const y = padY + row * (cellH + cellGap)
          return (
            <RoomCell
              key={r.roomId}
              room={r}
              x={x}
              y={y}
              w={cellW}
              h={cellH}
              hovered={hovered === r.roomId}
              onHover={onHover}
            />
          )
        })}
      </svg>
    </Box>
  )
}

function RoomCell({
  room: r,
  x,
  y,
  w,
  h,
  hovered,
  onHover,
}: {
  room: Room
  x: number
  y: number
  w: number
  h: number
  hovered: boolean
  onHover: (id: string | null) => void
}) {
  const isOther = r.occupiedByOtherBooking
  const count = r.assignedParticipants.length
  const isFull = count >= r.beds && r.beds > 0
  const isPartial = count > 0 && !isFull
  const fill = isOther
    ? PALETTE.occupiedOther
    : isFull
      ? PALETTE.full
      : isPartial
        ? PALETTE.filled
        : PALETTE.empty
  const stroke = hovered
    ? PALETTE.hover
    : isOther
      ? PALETTE.occupiedOtherText
      : count > 0
        ? PALETTE.filledBorder
        : PALETTE.emptyBorder
  const numberColor = isFull ? PALETTE.fullText : '#4E3149'

  // Avatar dots – up to 4 per room; rest collapses to "+N".
  const visible = r.assignedParticipants.slice(0, 4)
  const overflow = count - visible.length
  const avatarR = 11
  const avatarGap = 2
  const totalW = visible.length * (avatarR * 2) + Math.max(0, visible.length - 1) * avatarGap
  const startX = x + w / 2 - totalW / 2 + avatarR
  const avatarY = y + h - avatarR - 8

  return (
    <g
      onMouseEnter={() => onHover(r.roomId)}
      onMouseLeave={() => onHover(null)}
      style={{ cursor: 'default' }}
    >
      <rect
        x={x}
        y={y}
        width={w}
        height={h}
        fill={fill}
        stroke={stroke}
        strokeWidth={hovered ? 2 : 1}
        rx={6}
      />
      <text
        x={x + 8}
        y={y + 18}
        fontSize="12"
        fontWeight="700"
        fill={numberColor}
        fontFamily="Open Sans, system-ui, sans-serif"
      >
        {r.number}
      </text>
      <text
        x={x + w - 8}
        y={y + 18}
        fontSize="9"
        textAnchor="end"
        fill={isFull ? 'rgba(255,255,255,0.85)' : '#9B9499'}
        fontFamily="Open Sans, system-ui, sans-serif"
      >
        {r.roomType}
      </text>
      {isOther ? (
        <text
          x={x + w / 2}
          y={y + h / 2 + 4}
          fontSize="10"
          textAnchor="middle"
          fill={PALETTE.occupiedOtherText}
          fontStyle="italic"
          fontFamily="Open Sans, system-ui, sans-serif"
        >
          —
        </text>
      ) : (
        <>
          {visible.map((p, idx) => {
            const cx = startX + idx * (avatarR * 2 + avatarGap)
            return (
              <g key={p.participantId}>
                <title>{p.name}</title>
                <circle cx={cx} cy={avatarY} r={avatarR} fill={tintFor(p.participantId)} stroke="#fff" strokeWidth={1.5} />
                <text
                  x={cx}
                  y={avatarY + 3}
                  fontSize="9"
                  textAnchor="middle"
                  fill="#fff"
                  fontWeight="700"
                  fontFamily="Open Sans, system-ui, sans-serif"
                >
                  {initials(p.name)}
                </text>
              </g>
            )
          })}
          {overflow > 0 && (
            <g>
              <circle
                cx={startX + visible.length * (avatarR * 2 + avatarGap)}
                cy={avatarY}
                r={avatarR}
                fill="#fff"
                stroke={PALETTE.filledBorder}
                strokeWidth={1}
              />
              <text
                x={startX + visible.length * (avatarR * 2 + avatarGap)}
                y={avatarY + 3}
                fontSize="9"
                textAnchor="middle"
                fill={PALETTE.filledBorder}
                fontWeight="700"
                fontFamily="Open Sans, system-ui, sans-serif"
              >
                +{overflow}
              </text>
            </g>
          )}
        </>
      )}
      <text
        x={x + 8}
        y={y + 34}
        fontSize="9"
        fill={isFull ? 'rgba(255,255,255,0.85)' : '#9B9499'}
        fontFamily="Open Sans, system-ui, sans-serif"
      >
        {count}/{r.beds}
      </text>
    </g>
  )
}
