module chat

import setup
import rand
import msg
import db

type Payload = MakeIrcUser | MakeMatrixUser

pub struct MakeIrcUser {
pub:
	network_hostname string
	nick             string
}

pub struct MakeMatrixUser {}

pub struct Aliases {
mut:
	aliases []&Alias
}

[heap]
pub struct Alias {
pub mut:
	matrix string
	irc    string
}

pub struct Actor {
pub mut:
	queue Queue
	out   chan string
	cin   chan Payload
}

pub struct Queue {
pub mut:
	entries map[string]Say
}

pub enum System {
	irc
	matrix
}

type SayMsg = msg.IrcMsg | msg.MatrixMsg

pub struct Say {
pub:
	system  System
	network string
	name    string
	room    string
	message string
}

pub fn (self Say) str() string {
	return '>$self.system< name: "$self.name" room: "$self.room" msg: "$self.message"'
}

pub fn setup(config setup.Config) &Actor {
	return &Actor{
		out: chan string{cap: 100}
		cin: chan Payload{cap: 100}
	}
}

pub fn make_id() string {
	return rand.string(5)
}

pub fn (mut self Actor) say(chat System, name string, network string, room string, message string) {
	msg := Say{
		system: chat
		network: network
		name: name
		room: room
		message: message
	}
	id := make_id()
	self.queue.set(id, msg)
	println('chat.say [$id/$self.queue.entries.len] $msg')
	match self.out.try_push(id) {
		.success {}
		.not_ready { println('WARNING chat.out channel not ready. channel len $self.out.len') }
		.closed {}
	}
}

pub fn (mut self Queue) set(id string, msg Say) {
	self.entries[id] = msg
}

pub fn (mut self Queue) get(id string) Say {
	return self.entries[id]
}

pub fn (mut self Queue) len() int {
	return self.entries.len
}

pub fn (mut self Queue) delete(id string) {
	self.entries.delete(id)
}

pub fn (mut self Queue) next() ?Say {
	id := self.next_id() ?
	return self.entries[id]
}

pub fn (mut self Queue) next_id() ?string {
	if self.entries.len > 0 {
		return self.entries.keys()[0]
	} else {
		return error('empty')
	}
}

pub fn (mut self Queue) contains(name string) bool {
	return self.entries.keys().contains(name)
}

pub fn (mut self Queue) by_name(name string) []string {
	mut ids := []string{}
	for id, entry in self.entries {
		if entry.name == name {
			ids << id
		}
	}
	return ids
}

pub fn (mut self Aliases) match_irc(nick string) ?&Alias {
	for alias in self.aliases {
		if alias.irc == nick {
			println('chat.Aliases.match_irc $nick found $alias')
			return alias
		}
	}
	return error('not found')
}

pub fn (mut self Aliases) match_matrix(nick string) ?&Alias {
	for alias in self.aliases {
		if alias.matrix == nick {
			println('chat.Aliases.match_matrix $nick found $alias')
			return alias
		}
	}
	return error('not found')
}

pub fn (mut self Aliases) add(alias &Alias) &Alias {
	println('chat.Aliases.add $alias')
	self.aliases.prepend(alias)
	return self.aliases[0]
}

pub fn (mut self Alias) str() string {
	return 'matrix:$self.matrix irc:$self.irc'
}

pub fn alias_to_db(obj Alias) []db.SqlValue {
	mut row := []db.SqlValue{}
	row << db.SqlValue{
		name: 'matrix'
		value: db.SqlType(obj.matrix)
	}
	row << db.SqlValue{
		name: 'irc'
		value: db.SqlType(obj.irc)
	}
	return row
}