import React, { useCallback, useEffect, useState } from 'react';
import { Box, Button, Text, Spinner, color } from 'folds';
import { Method } from 'matrix-js-sdk';
import { useMatrixClient } from '../../../hooks/useMatrixClient';
import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback';
import { SettingTile } from '../../../components/setting-tile';
import {
  DECORATION_CATEGORIES,
  DECORATION_CDN,
  decorationUrl,
} from '../../lotus/avatarDecorations';
import { invalidateDecorationCache } from '../../../hooks/useAvatarDecoration';

const PROFILE_FIELD = 'io.lotus.avatar_decoration';
const CELL_SIZE = 72;

function DecorationPreviewCell({
  slug,
  name,
  selected,
  onSelect,
}: {
  slug: string;
  name: string;
  selected: boolean;
  onSelect: (slug: string) => void;
}) {
  return (
    <button
      type="button"
      title={name}
      aria-label={name}
      aria-pressed={selected}
      onClick={() => onSelect(slug)}
      style={{
        position: 'relative',
        width: CELL_SIZE,
        height: CELL_SIZE,
        flexShrink: 0,
        border: `2px solid ${selected ? color.Primary.Main : 'transparent'}`,
        borderRadius: '50%',
        background: color.SurfaceVariant.Container,
        cursor: 'pointer',
        padding: 0,
        boxShadow: selected ? `0 0 0 1px ${color.Primary.Main}` : 'none',
        overflow: 'hidden',
        outline: 'none',
      }}
    >
      <img
        src={`${DECORATION_CDN}/${slug}.png`}
        alt={name}
        loading="eager"
        decoding="async"
        style={{
          position: 'absolute',
          inset: 0,
          width: '100%',
          height: '100%',
          objectFit: 'contain',
          pointerEvents: 'none',
        }}
      />
    </button>
  );
}

export function ProfileDecoration() {
  const mx = useMatrixClient();
  const userId = mx.getUserId()!;

  const [current, setCurrent] = useState<string | null>(null);
  const [selected, setSelected] = useState<string | null>(null);

  useEffect(() => {
    mx.http
      .authedRequest<Record<string, string>>(
        Method.Get,
        `/profile/${encodeURIComponent(userId)}/${PROFILE_FIELD}`,
      )
      .then((res) => {
        const val = (res[PROFILE_FIELD] as string | undefined) ?? null;
        setCurrent(val);
        setSelected(val);
      })
      .catch(() => {
        setCurrent(null);
        setSelected(null);
      });
  }, [mx, userId]);

  const [saveState, save] = useAsyncCallback(
    useCallback(
      async (slug: string | null) => {
        await mx.http.authedRequest(
          Method.Put,
          `/profile/${encodeURIComponent(userId)}/${PROFILE_FIELD}`,
          undefined,
          { [PROFILE_FIELD]: slug ?? '' },
        );
        setCurrent(slug);
        invalidateDecorationCache(userId);
      },
      [mx, userId],
    ),
  );

  const saving = saveState.status === AsyncStatus.Loading;
  const hasChanges = selected !== current;

  const handleSelect = (slug: string) => {
    setSelected((prev) => (prev === slug ? null : slug));
  };

  const handleClear = () => setSelected(null);

  const handleSave = () => {
    if (!hasChanges || saving) return;
    save(selected);
  };

  return (
    <SettingTile
      title={
        <Text as="span" size="L400">
          Avatar Decoration
        </Text>
      }
      description={
        <Text size="T200" priority="300">
          Shown on your avatar to all Lotus Chat users.
        </Text>
      }
    >
      <Box direction="Column" gap="300">
        {/* Current selection preview */}
        <Box alignItems="Center" gap="300">
          <div
            style={{
              position: 'relative',
              width: CELL_SIZE,
              height: CELL_SIZE,
              flexShrink: 0,
              borderRadius: '50%',
              background: color.SurfaceVariant.Container,
              overflow: 'hidden',
            }}
          >
            {selected && (
              <img
                src={decorationUrl(selected)}
                alt="Selected decoration preview"
                style={{
                  position: 'absolute',
                  inset: 0,
                  width: '100%',
                  height: '100%',
                  objectFit: 'contain',
                  pointerEvents: 'none',
                }}
              />
            )}
          </div>
          <Box grow="Yes" direction="Column" gap="100">
            <Text size="T300">
              {selected
                ? (DECORATION_CATEGORIES.flatMap((c) => c.decorations).find(
                    (d) => d.slug === selected,
                  )?.name ?? selected)
                : 'None'}
            </Text>
            {selected && (
              <Button
                type="button"
                size="300"
                radii="300"
                variant="Critical"
                fill="None"
                onClick={handleClear}
              >
                <Text size="B300">Remove</Text>
              </Button>
            )}
          </Box>
          {hasChanges && (
            <Button
              type="button"
              size="400"
              radii="300"
              variant="Success"
              fill="Solid"
              onClick={handleSave}
              disabled={saving}
              before={saving ? <Spinner size="100" variant="Success" /> : undefined}
            >
              <Text size="B300">{saving ? 'Saving…' : 'Save'}</Text>
            </Button>
          )}
        </Box>

        {saveState.status === AsyncStatus.Error && (
          <Text size="T200" style={{ color: color.Critical.Main }}>
            Failed to save. Try again.
          </Text>
        )}

        {/* Category grid */}
        <div
          style={{
            maxHeight: 480,
            overflowY: 'auto',
            overflowX: 'hidden',
            paddingRight: 4,
            display: 'flex',
            flexDirection: 'column',
            gap: 24,
          }}
        >
          {DECORATION_CATEGORIES.map((category) => (
            <div key={category.id} style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
              <Text size="L400" style={{ opacity: 0.7 }}>
                {category.label}
              </Text>
              <div
                style={{
                  display: 'grid',
                  gridTemplateColumns: `repeat(auto-fill, ${CELL_SIZE}px)`,
                  gap: 20,
                }}
              >
                {category.decorations.map((d) => (
                  <DecorationPreviewCell
                    key={d.slug}
                    slug={d.slug}
                    name={d.name}
                    selected={selected === d.slug}
                    onSelect={handleSelect}
                  />
                ))}
              </div>
            </div>
          ))}
        </div>
      </Box>
    </SettingTile>
  );
}
