import type { Tone } from '@/components/Data';
import type { ReactNode } from 'react';
import type { GiteaIssue, GiteaLabel, GiteaPullRequest, GiteaUser } from './shared';
import { CircleCheck, CircleDot, GitMerge, GitPullRequest, GitPullRequestClosed } from 'lucide-react';
import { EmptyBlock, ErrorBlock, LoadingBlock, StatusIcon, StatusPill } from '@/components/Data';
import { serviceErrorMessage } from '../../hooks/useServiceConnection';
import { labelTextColor } from './shared';

// The small pieces every Gitea view repeats. These are now thin adapters over `components/Data` —
// they translate Gitea's vocabulary (open / closed / merged) into the design language's five tones
// and otherwise get out of the way. See docs/design-language-interface.md.
//
// The export names are unchanged so the ten call sites did not all have to move at once.

/**
 * Gitea's state vocabulary, mapped once.
 *
 * The non-obvious choice is CLOSED ISSUE → neutral rather than a colour of its own. Most issues in
 * any list are closed; giving them a tone paints most of the screen and leaves the open ones no
 * quieter than the rest. Neutral is what makes "open" findable — which is the only thing anyone is
 * scanning an issue list for. A closed PULL request is different: it was rejected, and that is a
 * real outcome worth marking, so it keeps `danger`.
 */
function stateOf(item: GiteaIssue | GiteaPullRequest): { tone: Tone; icon: typeof CircleDot; text: string } {
  const isPull = 'base' in item || !!(item as GiteaIssue).pull_request;
  const merged = (item as GiteaPullRequest).merged || (item as GiteaIssue).pull_request?.merged;

  if (merged) return { tone: 'info', icon: GitMerge, text: 'Merged' };
  if (item.state === 'open') {
    return { tone: 'success', icon: isPull ? GitPullRequest : CircleDot, text: 'Open' };
  }
  return isPull
    ? { tone: 'danger', icon: GitPullRequestClosed, text: 'Closed' }
    : { tone: 'neutral', icon: CircleCheck, text: 'Closed' };
}

export const Avatar = ({ user, size = 20 }: { user?: GiteaUser; size?: number }) => {
  const initial = (user?.full_name || user?.login || '?').charAt(0).toUpperCase();
  if (!user?.avatar_url) {
    return (
      <span
        className="inline-flex shrink-0 items-center justify-center rounded-full bg-muted text-xs font-medium text-muted-foreground"
        style={{ width: size, height: size }}
        title={user?.login}
      >
        {initial}
      </span>
    );
  }
  return (
    <img
      src={user.avatar_url}
      alt={user.login}
      title={user.login}
      className="shrink-0 rounded-full object-cover"
      style={{ width: size, height: size }}
      loading="lazy"
    />
  );
};

/**
 * The one place a raw colour is correct: a label's colour is data the user chose in Gitea, not a
 * decision this app gets to make. Everything else on a Gitea surface goes through a tone.
 */
export const LabelChip = ({ label }: { label: GiteaLabel }) => (
  <span
    className="inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium leading-none"
    style={{ backgroundColor: `#${label.color.replace('#', '')}`, color: labelTextColor(label.color) }}
    title={label.description}
  >
    {label.name}
  </span>
);

export const StateBadge = ({ item }: { item: GiteaIssue | GiteaPullRequest }) => {
  const { tone, icon, text } = stateOf(item);
  return (
    <StatusPill tone={tone} icon={icon}>
      {text}
    </StatusPill>
  );
};

/** The state marker for a dense list, where the full pill is too much furniture. */
export const StateIcon = ({ item }: { item: GiteaIssue | GiteaPullRequest }) => {
  const { tone, icon, text } = stateOf(item);
  return <StatusIcon tone={tone} icon={icon} title={text} />;
};

export const Loading = ({ label = 'Loading…' }: { label?: string }) => <LoadingBlock label={label} />;

export const ErrorState = ({ title, error }: { title: string; error: unknown }) => (
  <ErrorBlock title={title} message={serviceErrorMessage(error)} />
);

export const EmptyState = ({ title, hint }: { title: string; hint?: ReactNode }) => (
  <EmptyBlock title={title} hint={hint} />
);

/** A segmented open/closed filter, the control Gitea puts above every issue and PR list. */
type StateFilterProps = { value: 'open' | 'closed' | 'all'; onChange: (value: 'open' | 'closed' | 'all') => void };

export const StateFilter = ({ value, onChange }: StateFilterProps) => (
  <div className="inline-flex rounded-md border p-0.5 text-xs">
    {(['open', 'closed', 'all'] as const).map((state) => (
      <button
        key={state}
        type="button"
        onClick={() => onChange(state)}
        className={`rounded-md px-2.5 py-1 font-medium capitalize transition-colors ${
          value === state ? 'bg-primary/10 text-primary' : 'text-muted-foreground hover:text-foreground'
        }`}
      >
        {state}
      </button>
    ))}
  </div>
);
