/**
 * Pireon Admin API — the public payloads.
 *
 * Generated from openapi.yaml by `php artisan api:types`. Do not edit:
 * change the specification instead, and the contract test will hold the
 * API to it.
 */

/**
 * The same record's path in each language that has a translation. Feed
 * these straight into `<link rel="alternate" hreflang>`. Languages with
 * no translation are absent, so no advertised URL ever 404s.
 */
export type Alternates = Record<string, string>;

/**
 * Everything needed to render an image well server-side. A path alone
 * was never enough: without `width`/`height` the page reflows as images
 * arrive, without `srcset` every visitor downloads the original, and
 * without `alt` the page is not accessible.
 * 
 * Degrades on purpose — an upload whose derived versions are not ready
 * yet still carries a `url`, with the rest null, so the frontend renders
 * a plain `<img>` rather than a gap.
 */
export interface Image {
  /**
   * Absolute, because the frontend is on another host.
   */
  url: string;
  /**
   * Empty string when the image is decorative — that is what `alt=""`
   * means — never absent. Follows the requested language.
   */
  alt: string;
  width?: number;
  height?: number;
  aspect_ratio?: number;
  mime?: string;
  /**
   * Tiny blurred data URI to paint while the real image loads.
   */
  placeholder?: string;
  /**
   * Keyed by format, ready to use verbatim — build a `<picture>` with
   * AVIF first and WebP behind it. Only widths that actually exist are
   * listed, and an image is never scaled up.
   */
  srcset?: Record<string, string>;
}

/**
 * A call for contributors. The commitment fields are the point: time is
 * the scarce resource in a volunteer collective, and stating it plainly
 * is what lets someone decide.
 */
export interface PublicCall {
  id: number;
  locale: string;
  title: string;
  slug: string;
  description?: string;
  /**
   * The explicit exchange offered for unpaid work.
   */
  what_you_get?: string;
  status: 'open' | 'filled' | 'closed';
  hours_per_week?: number;
  duration_weeks?: number;
  total_hours?: number;
  seniority?: 'any' | 'junior' | 'mid' | 'senior';
  closes_at?: string;
  project: PublicProject;
  technologies: PublicTechnology[];
  alternates: Alternates;
  path?: string;
}

export interface PublicCategory {
  id: number;
  name?: string;
  slug?: string;
  description?: string;
  color?: string;
  position: number;
  pages_count: number;
}

export interface PublicClient {
  id: number;
  /**
   * A proper noun, so it is the same in every language.
   */
  name: string;
  slug: string;
  sector?: string;
  url?: string;
  /**
   * Its alt text is the organisation's name.
   */
  logo?: Image;
  projects_count: number;
}

export interface PublicIssue {
  number: number;
  title: string;
  url: string;
  labels: string[];
  is_good_first_issue: boolean;
  is_help_wanted: boolean;
  /**
   * Nobody has claimed it. A claimed issue is not an invitation.
   */
  is_available: boolean;
  comments: number;
  created_at?: string;
  repository: { full_name: string; url?: string; primary_language?: string; project?: { title: string; slug: string } };
}

export interface PublicMember {
  id: number;
  name: string;
  slug: string;
  headline?: string;
  bio?: string;
  avatar?: Image;
  github_username?: string;
  links: Record<string, string>;
  is_founder: boolean;
  /**
   * False for people who have left; their work is kept.
   */
  is_current: boolean;
  joined_at?: string;
  left_at?: string;
  /**
   * Their role on a project, when nested under one.
   */
  role?: string;
  technologies: PublicTechnology[];
  projects: PublicProject[];
  alternates: Alternates;
  path: string;
}

export interface PublicPage {
  id: number;
  locale: string;
  title?: string;
  slug?: string;
  excerpt?: string;
  body?: string;
  meta_title?: string;
  meta_description?: string;
  status: string;
  is_featured: boolean;
  featured_image?: Image;
  published_at?: string;
  /**
   * When the record leaves the site. Enforced by the query itself, so
   * it holds whether or not anything is running. Use it to expire a
   * cache downstream at the same moment.
   */
  unpublish_at?: string;
  updated_at: string;
  category: PublicCategory;
  /**
   * The ones named in this language, to link to the blog filtered by each.
   */
  tags: ({ name: string; slug: string })[];
  /**
   * The member who signs it, when they have a public profile.
   */
  byline?: { name: string; slug: string; headline?: string; avatar?: Image; path: string };
  alternates: Alternates;
  path?: string;
}

export interface PublicProject {
  id: number;
  locale: string;
  title: string;
  slug: string;
  tagline?: string;
  /**
   * Detail endpoint only.
   */
  description?: string;
  /**
   * Why the technical choices were made. Detail endpoint only.
   */
  decisions?: string;
  /**
   * What went wrong and what was learned. Detail endpoint only.
   */
  postmortem?: string;
  /**
   * What a search engine or a chat preview should show instead of the
   * title. Detail endpoint only.
   */
  meta_title?: string;
  /**
   * Detail endpoint only.
   */
  meta_description?: string;
  status: 'idea' | 'active' | 'paused' | 'completed' | 'archived';
  is_featured: boolean;
  /**
   * Flagged directly, or carrying at least one open call.
   */
  needs_help: boolean;
  cover_image?: Image;
  /**
   * Screenshots and before-and-after, in the order they were arranged
   * in the panel. **Detail endpoint only** — a listing of twenty
   * projects has no use for every screenshot of each one.
   */
  gallery: (Image & { caption?: string })[];
  demo_url?: string;
  /**
   * The NGO or association the work serves. Used to be two free-text
   * fields, which made the same organisation two different things.
   */
  client?: PublicClient;
  services: PublicService[];
  testimonials: PublicTestimonial[];
  talks: PublicTalk[];
  started_at?: string;
  ended_at?: string;
  published_at?: string;
  /**
   * When the record leaves the site. Enforced by the query itself, so
   * it holds whether or not anything is running. Use it to expire a
   * cache downstream at the same moment.
   */
  unpublish_at?: string;
  updated_at: string;
  technologies: PublicTechnology[];
  members: PublicMember[];
  lead: PublicMember;
  calls: PublicCall[];
  repositories: PublicRepository[];
  /**
   * Its board in TaskStream, if it has one. `showcase_url` answers without a token: roadmap, releases, the sprint under way and tickets labelled good-first-issue.
   */
  taskstream?: { key: string; url: string; web_url: string; showcase_url: string };
  alternates: Alternates;
  path?: string;
}

/**
 * Mirrored from the git provider and refreshed hourly.
 */
export interface PublicRepository {
  id: number;
  provider: 'github' | 'gitlab' | 'gitea';
  full_name: string;
  url?: string;
  description?: string;
  primary_language?: string;
  /**
   * Bytes of code per language.
   */
  languages: Record<string, number>;
  topics: string[];
  license?: string;
  stars: number;
  forks: number;
  contributors_count: number;
  open_issues_count: number;
  is_archived: boolean;
  /**
   * Nothing pushed for six months. Lets the frontend avoid presenting
   * dead work as live.
   */
  is_dormant: boolean;
  pushed_at?: string;
  synced_at?: string;
  good_first_issues: PublicIssue[];
}

export interface PublicSearchResult {
  type: 'page' | 'project' | 'service' | 'call' | 'member' | 'technology';
  id: number;
  title: string;
  /**
   * Plain text around the first match.
   */
  excerpt: string;
  path?: string;
  /**
   * Higher is a better match. Only comparable within one response.
   */
  score: number;
}

export interface PublicService {
  id: number;
  locale: string;
  title: string;
  slug: string;
  tagline?: string;
  /**
   * Detail endpoint only.
   */
  description?: string;
  /**
   * What a search engine or a chat preview should show instead of the
   * title. Detail endpoint only.
   */
  meta_title?: string;
  /**
   * Detail endpoint only.
   */
  meta_description?: string;
  /**
   * A Heroicons name, e.g. `heroicon-o-code-bracket`.
   */
  icon?: string;
  is_featured: boolean;
  position: number;
  /**
   * So a cache downstream can tell whether its copy is still the
   * current one.
   */
  updated_at?: string;
  /**
   * The published work that backs the offer. Detail endpoint only.
   */
  projects: PublicProject[];
  technologies: PublicTechnology[];
  testimonials: PublicTestimonial[];
  alternates: Alternates;
  path?: string;
}

export interface PublicTalk {
  id: number;
  /**
   * Not translated: the name of a talk given once, in one language.
   */
  title: string;
  language: string;
  summary?: string;
  event: string;
  city?: string;
  held_at?: string;
  video_url?: string;
  slides_url?: string;
  speaker?: PublicMember;
}

export interface PublicTechnology {
  id: number;
  /**
   * Not translated — technology names are proper nouns.
   */
  name: string;
  slug: string;
  category: 'language' | 'framework' | 'datastore' | 'infrastructure' | 'tool' | 'practice';
  color?: string;
  icon?: string;
  /**
   * The technology's own logo. Its `alt` is the technology's name —
   * there is nothing to write and nothing to get wrong.
   */
  logo?: Image;
  website?: string;
  /**
   * Radar placement. Null for technologies used but not placed.
   */
  ring?: 'adopt' | 'trial' | 'assess' | 'hold';
  description?: string;
  /**
   * Why it sits in that ring.
   */
  radar_note?: string;
  projects_count: number;
  members_count: number;
}

export interface PublicTestimonial {
  id: number;
  quote: string;
  /**
   * The language it was actually said in.
   */
  original_locale: string;
  /**
   * False when the quote you are reading was translated by us. Say so —
   * "translated from Spanish" — rather than implying they phrased it
   * that way.
   */
  is_original: boolean;
  author: { name: string; role?: string; avatar?: Image };
  given_at?: string;
  client?: PublicClient;
}

/**
 * Either a plain string (applies to the active language) or an object
 * keyed by locale.
 */
export type TranslatedField = Record<string, string>;

/** What each public endpoint answers with, under `data`. */
export interface PublicApiPayloads {
  '/public/v1/site': { locales: ({ code: string; name: string; flag: string; is_default: boolean })[]; default_locale: string; content_version: number; submissions_enabled: boolean; stats: { projects: number; active_projects: number; members: number; open_calls: number; good_first_issues: number; stars: number } };
  '/public/v1/slugs': Record<string, ({ id: number; updated_at: string; alternates: Record<string, string> })[]>;
  '/public/v1/redirects': ({ from: string; to: string; status: 301 | 302; locale?: string })[];
  '/public/v1/search': PublicSearchResult[];
  '/public/v1/tags': ({ name: string; slug: string; count: number })[];
  '/public/v1/projects': PublicProject[];
  '/public/v1/projects/{slug}': PublicProject;
  '/public/v1/members': PublicMember[];
  '/public/v1/members/{slug}': PublicMember;
  '/public/v1/calls': PublicCall[];
  '/public/v1/calls/{slug}': PublicCall;
  '/public/v1/services': PublicService[];
  '/public/v1/services/{slug}': PublicService;
  '/public/v1/clients': PublicClient[];
  '/public/v1/testimonials': PublicTestimonial[];
  '/public/v1/talks': PublicTalk[];
  '/public/v1/pages': PublicPage[];
  '/public/v1/pages/{slug}': PublicPage;
  '/public/v1/technologies': PublicTechnology[];
  '/public/v1/radar': PublicTechnology[];
  '/public/v1/good-first-issues': PublicIssue[];
}
