import { useEffect, useRef, useState } from 'react';
import { useConnection } from '../../context/ConnectionContext';
import { useServerData } from '../../context/ServerDataContext';
import { useSettings } from '../../context/SettingsContext';
import { UserAvatar } from '../UserAvatar';

const JUST_NOW_MINUTES = 15;
const GREEN_MINUTES = 60;
const OFFLINE_AFTER_HOURS = 72;
const CLOCK_TICK_MS = 30000;

function minutesSince(iso) {
  if (!iso) return null;
  const ms = Date.now() - new Date(iso).getTime();
  if (Number.isNaN(ms) || ms < 0) return 0;
  return ms / 60000;
}

function PresenceIndicator({ lastSeenAt }) {
  const minutes = minutesSince(lastSeenAt);

  if (minutes == null || minutes / 60 > OFFLINE_AFTER_HOURS) {
    return (
      <div className="member-presence member-presence--offline">
        <span className="member-presence-dot member-presence-dot--offline" aria-hidden="true" />
        Offline
      </div>
    );
  }

  const isGreen = minutes < GREEN_MINUTES;
  const wholeMinutes = Math.floor(minutes);
  const wholeHours = Math.floor(minutes / 60);
  const label =
    minutes < JUST_NOW_MINUTES
      ? 'Just now'
      : minutes < 60
        ? `Last seen ${wholeMinutes} minute${wholeMinutes === 1 ? '' : 's'} ago`
        : `Last seen ${wholeHours} hour${wholeHours === 1 ? '' : 's'} ago`;

  return (
    <div className={`member-presence ${isGreen ? 'member-presence--online' : 'member-presence--away'}`}>
      <span
        className={`member-presence-dot ${isGreen ? 'member-presence-dot--online' : 'member-presence-dot--away'}`}
        aria-hidden="true"
      />
      {label}
    </div>
  );
}

function formatMemberTime(timezone, now) {
  try {
    return new Intl.DateTimeFormat(undefined, {
      timeZone: timezone,
      hour: 'numeric',
      minute: '2-digit',
    }).format(now);
  } catch {
    return null;
  }
}

function StatusText({ isSelf, status, onSave }) {
  const [editing, setEditing] = useState(false);
  const [draft, setDraft] = useState(status || '');
  const inputRef = useRef(null);

  useEffect(() => {
    if (editing) inputRef.current?.focus();
  }, [editing]);

  if (!isSelf) {
    return <blockquote className="member-status">{status || 'No status set.'}</blockquote>;
  }

  const commit = () => {
    setEditing(false);
    const trimmed = draft.trim();
    if (trimmed !== (status || '')) onSave(trimmed);
  };

  if (editing) {
    return (
      <input
        ref={inputRef}
        type="text"
        className="member-status member-status--editing"
        value={draft}
        onChange={(e) => setDraft(e.target.value)}
        onKeyDown={(e) => {
          if (e.key === 'Enter') {
            e.preventDefault();
            commit();
          }
        }}
        onBlur={commit}
      />
    );
  }

  return (
    <blockquote
      className="member-status member-status--editable"
      onClick={() => {
        setDraft(status || '');
        setEditing(true);
      }}
    >
      {status || 'No status set.'}
    </blockquote>
  );
}

export function MembersPanel() {
  const { account, api, updateAccount } = useConnection();
  const { users, usersLoaded } = useServerData();
  const { showMemberTimezones } = useSettings();
  const [now, setNow] = useState(() => new Date());

  useEffect(() => {
    const timer = setInterval(() => setNow(new Date()), CLOCK_TICK_MS);
    return () => clearInterval(timer);
  }, []);

  const self = account?.username.toLowerCase();
  const members = users
    .filter((user) => !user.removed)
    .sort((a, b) => {
      const aSelf = a.username.toLowerCase() === self;
      const bSelf = b.username.toLowerCase() === self;
      if (aSelf !== bSelf) return aSelf ? -1 : 1;
      const aTime = a.lastSeenAt ? new Date(a.lastSeenAt).getTime() : -Infinity;
      const bTime = b.lastSeenAt ? new Date(b.lastSeenAt).getTime() : -Infinity;
      if (aTime !== bTime) return bTime - aTime;
      return a.displayName.localeCompare(b.displayName);
    });

  return (
    <div className="members-container">
      {!usersLoaded && members.length === 0 && (
        <div className="panel-loading-hint">Loading members…</div>
      )}
      <ul className="members-list">
        {members.map((member, index) => {
          const isSelf = member.username.toLowerCase() === self;
          const memberTime = member.timezone ? formatMemberTime(member.timezone, now) : null;
          return (
            <li
              key={member.username}
              className={`member-card${index % 2 === 1 ? ' member-card--alt' : ''}`}
            >
              <UserAvatar
                user={{
                  avatarUrl: isSelf ? account.avatarUrl : api?.avatarUrl(member.avatar),
                }}
                size={36}
                className="member-avatar"
              />
              <div className="member-main">
                <div className="member-name">
                  {member.displayName}
                  {isSelf ? (
                    <span className="member-you-tag"> (you)</span>
                  ) : (
                    // Same shape and placement as the "(you)" tag above, so the
                    // column reads `Mike (4:00 PM)`. A member who has never set
                    // a timezone renders nothing — we can't know their local
                    // time and must not imply one.
                    showMemberTimezones &&
                    memberTime && <span className="member-timezone"> ({memberTime})</span>
                  )}
                </div>
                <div className="member-email">{member.username}</div>
                <PresenceIndicator lastSeenAt={member.lastSeenAt} />
              </div>
              <StatusText
                isSelf={isSelf}
                status={member.status}
                onSave={(status) => updateAccount({ status })}
              />
            </li>
          );
        })}
      </ul>
    </div>
  );
}
