declare const brand: unique symbol;

// branded typing
export type Brand<T, TBrand extends string> = T & {
  [brand]: TBrand;
};

export type Player = Brand<string, 'Player'>;
export type CardId = Brand<number, 'CardId'>;
// export type FactionId = 'a' | 'c' | 'm';
export type FactionId = 0 | 1 | 2;
export type FascistId = 3;
export type FrontId = 0 | 1 | 2 | 3;
export type ClosestToDefeat = 4;
export type ClosestToVictory = 5;
// export type FrontId = 'a' | 'm' | 'n' | 's';

export interface Front {
  value: number;
  contributions: FactionId[];
  status: 'Victory' | 'Defeat' | null;
}

export interface Game {
  // TODO: why is this needed?
  [index: number]: any;
  // RTT
  active: Player | Player[] | 'None' | null;
  log: string[];
  seed: number;
  state: string | null;
  undo: Game[];
  result?: string;
  victory?: string;
  // Game specific
  active_abilities: number[];
  turn: number;
  year: number;
  bag_of_glory: FactionId[];
  bonuses: number[];
  current_events: CardId[];
  discard: number[][];
  engine: EngineNode[];
  /**
   * Set to faction whos turn it is or null if not player turn
   * Used to determine who can spend Hero Points. Could be the case
   * a player becomes active in another players turn.
   */
  faction_turn: FactionId | null;
  /**
   * First player of current game turn
   */
  first_player: FactionId | null;
  fronts: Front[];
  glory: FactionId[];
  hands: CardId[][];
  hero_points: number[];
  initiative: FactionId;
  medallions: number[][];
  /**
   * Set to FactionId if player has earned the Momentum medallion
   * during the current turn
   */
  momentum: FactionId | null;
  played_card: CardId | null;
  player_order: Player[];
  selected_cards: CardId[][];
  fascist_cards?: CardId[]; // used for specific events
  tableaus: CardId[][];
  /**
   * Used for event effect that allows Anarchist to put an event
   * card on top of the deck
   */
  top_of_events_deck: CardId | null;
  tracks: number[];
  trash: CardId[][];
  triggered_track_effects: number[];
  used_medallions: number[];
  glory_current_year?: boolean[] | null;
  fascist: 0 | 1 | 2;
  card_played: 0 | 1;
  hidden_bag?: 0 | 1;
  /**
   * Set to 1 if player has played card to their tableau and still
   * needs to use action points
   */
  can_use_ap: 0 | 1;
  /**
   * Set to 1 if player has played card to their tableau and still
   * needs to use morale bonus. Note bonus still needs to be on, this 
   * just determines if player has used it or not
   */
  can_use_mb: 0 | 1;
}

export interface View {
  log: number | string[];
  prompt: string | null;
  actions?: any;
  victory?: string;
  selected_cards: number[];
  bag_of_glory?: Game['bag_of_glory'];
  bonuses: Game['bonuses'];
  current_events: CardId[];
  first_player: Game['first_player'];
  fronts: Game['fronts'];
  glory: Game['glory'];
  hand: number[];
  // discard: number[];
  // deck: number[];
  fascist_cards?: number[];
  trash?: number[];
  hero_points: Game['hero_points'];
  initiative: Game['initiative'];
  medallions: Game['medallions'];
  played_card: Game['played_card'];
  player_order: FactionId[];
  tableaus: Game['tableaus'];
  tracks: number[];
  triggered_track_effects: Game['triggered_track_effects'];
  used_medallions: Game['used_medallions'];
  year: number;
  fascist?: number;
}

export type States = {
  [key: string]: any;
};

export type EngineNode = FunctionNode | StateNode | SeqNode;

export interface FunctionNode {
  t: 'f';
  f: string; // function to be triggered
  a?: any; // args
  r?: 0 | 1; // 1 if resolved
}

export interface SeqNode {
  t: 's'; // Type
  c: EngineNode[];
}

export interface StateNode<T = any> {
  t: 'l';
  s: string; // State
  p: FactionId | 'None' | 'all' | FactionId[]; // Player
  a?: T; // args
  r?: 0 | 1; // 1 if resolved
}

export interface CardBase {
  id: number;
  title: string;
}

export type Card = EventCard | PlayerCard;

export interface EventCard extends CardBase {
  type: 'ec';
  year: number;
  effects: Effect[];
  test: {
    front: FrontId;
    value: number;
    pass: Effect;
    fail: Effect;
  };
}

export type Icon =
  | 'add_to_front'
  | 'collectivization'
  | 'd_collectivization'
  | 'd_foreign_aid'
  | 'd_government'
  | 'd_liberty'
  | 'd_soviet_support'
  | 'draw_card'
  | 'foreign_aid'
  | 'government'
  | 'government_to_center'
  | 'liberty'
  | 'soviet_support'
  | 'teamwork_on';

export interface PlayerCard extends CardBase {
  type: 'pc';
  strength: number;
  effects: Effect[];
  icons: Icon[];
}

export type EffectSource = 'player_event' | 'fascist_event' | 'fascist_test' | 'track_icon' | 'momentum' | 'tr0' | 'tr1' | 'tr2' | 'tr3' | 'tr4';

export interface Effect {
  type:
    | 'attack'
    | 'track'
    | 'bonus'
    | 'hero_points'
    | 'front'
    | 'function' // Use for unqique effects
    | 'medallion'
    | 'draw_card'
    | 'play_card'
    | 'swap_card_tableau_hand'
    | 'state'
    | 'add_card_to_tableau'
    | 'remove_blank_marker'
    | 'return_card'
    | 'take_hero_points';
  target: string | number | FactionId;
  value: number;
  faction?: FactionId | 'i';
}

export interface StaticData {
  cards: Card[];
  fronts: Array<{
    id: number;
    name: string;
    left: number;
    top: number;
  }>;
  medallions: Array<{
    id: number;
    name: string;
    tooltip: string;
  }>;
  tracks: Array<{
    id: number;
    action: EffectSource;
    name: string;
    triggers: Array<null | Effect>;
  }>;
}

// #region engine node args

export interface EngineNodeArgsBase {
  /**
   * If set, node was added to engine as result of given effect.
   * Used for prompts
   */
  src?: EffectSource;
}

export interface PlayCardArgs extends EngineNodeArgsBase {
}

export interface PlayerTurnArgs extends EngineNodeArgsBase {
}

// #endregion