#pragma once
#include "common/bitfield.h"
#include "common/fifo_queue.h"
#include "types.h"
#include <array>
#include <memory>

class StateWrapper;

class TimingEvent;
class Controller;
class MemoryCard;

class Pad final
{
public:
  Pad();
  ~Pad();

  void Initialize();
  void Shutdown();
  void Reset();
  bool DoState(StateWrapper& sw);

  Controller* GetController(u32 slot) const { return m_controllers[slot].get(); }
  void SetController(u32 slot, std::unique_ptr<Controller> dev);

  MemoryCard* GetMemoryCard(u32 slot) { return m_memory_cards[slot].get(); }
  void SetMemoryCard(u32 slot, std::unique_ptr<MemoryCard> dev);

  u32 ReadRegister(u32 offset);
  void WriteRegister(u32 offset, u32 value);

private:
  static constexpr u32 NUM_SLOTS = 2;

  enum class State : u32
  {
    Idle,
    Transmitting,
    WaitingForACK
  };

  enum class ActiveDevice : u8
  {
    None,
    Controller,
    MemoryCard
  };

  union JOY_CTRL
  {
    u16 bits;

    BitField<u16, bool, 0, 1> TXEN;
    BitField<u16, bool, 1, 1> SELECT;
    BitField<u16, bool, 2, 1> RXEN;
    BitField<u16, bool, 4, 1> ACK;
    BitField<u16, bool, 6, 1> RESET;
    BitField<u16, u8, 8, 2> RXIMODE;
    BitField<u16, bool, 10, 1> TXINTEN;
    BitField<u16, bool, 11, 1> RXINTEN;
    BitField<u16, bool, 12, 1> ACKINTEN;
    BitField<u16, u8, 13, 1> SLOT;
  };

  union JOY_STAT
  {
    u32 bits;

    BitField<u32, bool, 0, 1> TXRDY;
    BitField<u32, bool, 1, 1> RXFIFONEMPTY;
    BitField<u32, bool, 2, 1> TXDONE;
    BitField<u32, bool, 7, 1> ACKINPUT;
    BitField<u32, bool, 9, 1> INTR;
    BitField<u32, u32, 11, 21> TMR;
  };

  union JOY_MODE
  {
    u16 bits;

    BitField<u16, u8, 0, 2> reload_factor;
    BitField<u16, u8, 2, 2> character_length;
    BitField<u16, bool, 4, 1> parity_enable;
    BitField<u16, u8, 5, 1> parity_type;
    BitField<u16, u8, 8, 1> clk_polarity;
  };

  bool IsTransmitting() const { return m_state != State::Idle; }
  bool CanTransfer() const { return m_transmit_buffer_full && m_JOY_CTRL.SELECT && m_JOY_CTRL.TXEN; }

  TickCount GetTransferTicks() const { return static_cast<TickCount>(ZeroExtend32(m_JOY_BAUD) * 8); }

  // From @JaCzekanski
  // ACK lasts ~96 ticks or approximately 2.84us at master clock (not implemented).
  // ACK delay is between 6.8us-13.7us, or ~338 ticks at master clock for approximately 9.98us.
  // Memory card responds faster, approximately 5us or ~170 ticks.
  static constexpr TickCount GetACKTicks(bool memory_card) { return memory_card ? 170 : 450; }

  void SoftReset();
  void UpdateJoyStat();
  void TransferEvent(TickCount ticks_late);
  void BeginTransfer();
  void DoTransfer(TickCount ticks_late);
  void DoACK();
  void EndTransfer();
  void ResetDeviceTransferState();

  std::array<std::unique_ptr<Controller>, NUM_SLOTS> m_controllers;
  std::array<std::unique_ptr<MemoryCard>, NUM_SLOTS> m_memory_cards;

  std::unique_ptr<TimingEvent> m_transfer_event;
  State m_state = State::Idle;

  JOY_CTRL m_JOY_CTRL = {};
  JOY_STAT m_JOY_STAT = {};
  JOY_MODE m_JOY_MODE = {};
  u16 m_JOY_BAUD = 0;

  ActiveDevice m_active_device = ActiveDevice::None;
  u8 m_receive_buffer = 0;
  u8 m_transmit_buffer = 0;
  u8 m_transmit_value = 0;
  bool m_receive_buffer_full = false;
  bool m_transmit_buffer_full = false;
};

extern Pad g_pad;