import dayjs from 'dayjs';
import relativeTime from 'dayjs/plugin/relativeTime';
import { filesize } from 'filesize';

import type { Container, ContainerPort } from '../store/containersSlice/types';
import { capitalize } from './strings';

dayjs.extend(relativeTime);

// Human-readable byte size, e.g. 12.29 GB.
export const formatBytes = (bytes: number | null | undefined): string => {
  if (!bytes || bytes <= 0) return '0 B';
  return filesize(bytes, { standard: 'jedec', round: 2 });
};

// Relative time from an ISO/parseable timestamp string, e.g. "7 seconds ago",
// "a minute ago", "2 weeks ago". Returns '—' for empty/invalid input.
export const formatRelativeTime = (value: string | null | undefined, withoutSuffix?: boolean): string => {
  if (!value) return '—';
  const d = dayjs(value);
  return d.isValid() ? d.fromNow(withoutSuffix) : '—';
};

// Docker-style port list, e.g. "0.0.0.0:8080->80/tcp, 443/tcp". Returns '' for
// no ports so the caller can fall back to a placeholder.
export const formatPorts = (ports: ContainerPort[] | null): string => {
  if (!ports || ports.length === 0) return '';
  return ports
    .map(p => {
      const proto = p.protocol || 'tcp';
      if (p.host_port) {
        const host = p.host_ip ? `${p.host_ip}:` : '';
        return `${host}${p.host_port}->${p.container_port}/${proto}`;
      }
      return `${p.container_port}/${proto}`;
    })
    .join(', ');
};

// Format a Unix timestamp (seconds) as the legacy host-page format:
// `YYYY-MM-DD HH:MM±HH:MM` (no seconds), or with seconds when `withSeconds`
// is true (matches the Measurements widget output).
//
// Returns `fallback` (default 'unknown') if the timestamp is falsy or invalid.
export interface FormatTimestampOptions {
  withSeconds?: boolean;
  fallback?: string;
}

export const formatTimestamp = (
  ts: number | null | undefined,
  { withSeconds = false, fallback = 'unknown' }: FormatTimestampOptions = {}
): string => {
  if (!ts) return fallback;
  const d = dayjs.unix(ts);
  if (!d.isValid()) return fallback;
  // `Z` renders the local UTC offset as ±HH:mm.
  return d.format(withSeconds ? 'YYYY-MM-DD HH:mm:ssZ' : 'YYYY-MM-DD HH:mmZ');
};

// Docker-style container status, e.g. "Up 3 hours (healthy)", "Exited 2 days
// ago". Appends the health/status from the engine's `details` when present.
export const formatContainerStatus = (r: Container): string => {
  const state = r.state;
  if (!state) return '—';

  let result: string;
  switch (state) {
    case 'running':
      result = r.started_at ? `Up ${formatRelativeTime(r.started_at, true)}` : 'Up';
      break;
    case 'paused':
      // Docker formats paused containers as "Up <time> (Paused)".
      result = r.started_at ? `Up ${formatRelativeTime(r.started_at, true)} (Paused)` : 'Up (Paused)';
      break;
    case 'exited':
    case 'stopped':
      result = r.finished_at ? `Exited ${formatRelativeTime(r.finished_at)}` : 'Exited';
      break;
    default:
      result = capitalize(state);
  }

  const health =
    (r.details?.Status as string | undefined) ??
    ((r.details?.Health as { Status?: string } | undefined)?.Status);
  if (health) result += ` (${health})`;
  return result;
};
