package pnyx

import (
	"fmt"

	"github.com/google/uuid"
)

type ChannelID byte

const (
  MODE_RAW ModeID = iota
  MODE_AUDIO

  AUDIO_SET_SAMPLE_RATE = iota
  AUDIO_GET_SAMPLE_RATE
)

type ModeID uint8
type CommandID uint8
type Permission string

type Channel struct {
  id ChannelID
  name string
  modes map[ModeID]Mode
  members []*ServerSession
}

func(channel *Channel) Data(session *ServerSession, mode ModeID, data []byte) {
  m, has_mode := channel.modes[mode]
  if has_mode {
    m.Data(session, channel.id, channel.members, data)
  }
}

func(channel *Channel) Command(session *ServerSession, command byte, request_id uuid.UUID, mode_id ModeID, data []byte) error {
  mode, has_mode := channel.modes[mode_id]
  if has_mode == false {
    return fmt.Errorf("Channel has no mode 0x%02x", mode)
  } else {
    return mode.Command(session, command, request_id, channel.id, channel.members, data)
  }
}

func(channel *Channel) Join(client PeerID, session SessionID) {
}

func(channel *Channel) Leave(client PeerID, session SessionID) {
}

type Mode interface {
  Command(session *ServerSession, command byte, request_id uuid.UUID, channel_id ChannelID, members []*ServerSession, data []byte) error
  Data(session *ServerSession, channel_id ChannelID, members []*ServerSession, data []byte)

  Join(client PeerID, session SessionID)
  Leave(client PeerID, session SessionID)
}

func multiplex_without_sender(origin SessionID, packet *Packet, sessions []*ServerSession) {
  for _, session := range(sessions) {
    if session.ID == origin {
      continue
    }

    session.OutgoingPackets <- packet
  }
}

func multiplex(packet *Packet, sessions []*ServerSession) {
  for _, session := range(sessions) {
    session.OutgoingPackets <- packet
  }
}

type RawMode struct {
}

func(mode *RawMode) Command(session *ServerSession, command byte, request_id uuid.UUID, channel_id ChannelID, members []*ServerSession, data []byte) error {
  return fmt.Errorf("unknown raw mode command 0x%02x", command)
}

func(mode *RawMode) Data(session *ServerSession, channel_id ChannelID, members []*ServerSession, data []byte) {
  new_packet := NewChannelPeerPacket(session.Peer, channel_id, MODE_RAW, data)
  multiplex_without_sender(session.ID, new_packet, members)
}

func(mode *RawMode) Join(client PeerID, session SessionID) {
}
func(mode *RawMode) Leave(client PeerID, session SessionID) {
}

type SampleRate byte
const (
  SAMPLE_RATE_UNSET SampleRate = 0xFF
  SAMPLE_RATE_24KHZ = 0x01
  SAMPLE_RATE_48KHZ = 0x02
)

type AudioMode struct {
  SampleRate SampleRate
}

func(mode *AudioMode) Command(session *ServerSession, command byte, request_id uuid.UUID, channel_id ChannelID, members []*ServerSession, data []byte) error {
  switch command {
  case AUDIO_SET_SAMPLE_RATE:
    if len(data) == 1 {
      switch SampleRate(data[0]) {
      case SAMPLE_RATE_24KHZ:
        fallthrough
      case SAMPLE_RATE_48KHZ:
        mode.SampleRate = SampleRate(data[0])
        update_packet := NewChannelCommandPacket(request_id, channel_id, MODE_AUDIO, AUDIO_SET_SAMPLE_RATE, data)
        multiplex(update_packet, members)
        return nil
      default:
        return fmt.Errorf("Invalid sample rate: %x", data[0])
      }
    } else {
      return fmt.Errorf("Invalid AUDIO_SET_SAMPLE_RATE payload: %x", data)
    }
  case AUDIO_GET_SAMPLE_RATE:
    session.OutgoingPackets <- NewChannelCommandPacket(request_id, channel_id, MODE_AUDIO, AUDIO_SET_SAMPLE_RATE, []byte{byte(mode.SampleRate)})
    return nil
  default:
    return fmt.Errorf("unknown audio mode command 0x%02x", command)
  }
}

func(mode *AudioMode) Data(session *ServerSession, channel_id ChannelID, members []*ServerSession, data []byte) {
  new_packet := NewChannelPeerPacket(session.Peer, channel_id, MODE_AUDIO, data)
  multiplex_without_sender(session.ID, new_packet, members)
}

func(mode *AudioMode) Join(client PeerID, session SessionID) {
}
func(mode *AudioMode) Leave(client PeerID, session SessionID) {
}
