// Copyright 2020 - 2021 Martin Dosch.
// Use of this source code is governed by the BSD-2-clause
// license that can be found in the LICENSE file.

package main

import (
	"log"

	"github.com/beevik/etree"  // BSD-2-clause
	"github.com/mattn/go-xmpp" // BSD-3-Clause
)

func sendIQ(client *xmpp.Client, iqc chan xmpp.IQ, target string,
	iQtype string, content string) (xmpp.IQ, error) {
	var iq xmpp.IQ
	id := getID()
	c := make(chan xmpp.IQ)
	go getIQ(client, id, c, iqc)
	_, err := client.RawInformation(client.JID(), target, id,
		iQtype, content+"\n")
	if err != nil {
		return iq, err
	}
	iq = <-c
	return iq, nil
}

func getIQ(client *xmpp.Client, id string, c chan xmpp.IQ,
	iqc chan xmpp.IQ) {
	for {
		iq := <-iqc
		if iq.ID == id {
			c <- iq
			return
		}
	}
}

func rcvStanzas(client *xmpp.Client, iqc chan xmpp.IQ, msgc chan xmpp.Chat) {
	for {
		received, err := client.Recv()
		if err != nil {
			log.Println(err)
		}
		switch v := received.(type) {
		case xmpp.Chat:
			msgc <- v
		case xmpp.IQ:
			switch v.Type {
			case "get":
				var xmlns *etree.Attr
				iq := etree.NewDocument()
				err = iq.ReadFromBytes(v.Query)
				if err != nil {
					log.Println("Couldn't parse IQ:",
						string(v.Query), err)
				}
				query := iq.SelectElement("query")
				if query != nil {
					xmlns = query.SelectAttr("xmlns")
				}
				switch xmlns.Value {
				case nsDiscoInfo:
					root := etree.NewDocument()
					reply := root.CreateElement("iq")
					reply.CreateAttr("type", "result")
					reply.CreateAttr("from", client.JID())
					reply.CreateAttr("to", v.From)
					reply.CreateAttr("id", v.ID)
					replyQuery := reply.CreateElement("query")
					replyQuery.CreateAttr("xmlns", nsDiscoInfo)
					identity := replyQuery.CreateElement("identity")
					identity.CreateAttr("category", "client")
					identity.CreateAttr("type", "bot")
					identity.CreateAttr("name", "go-sendxmpp")
					feat := replyQuery.CreateElement("feature")
					feat.CreateAttr("var", nsDiscoInfo)
					xmlString, err := root.WriteToString()
					if err == nil {
						_, err = client.SendOrg(xmlString)
						if err != nil {
							log.Println(err)
						}
					}
				default:
					root := etree.NewDocument()
					reply := root.CreateElement("iq")
					reply.CreateAttr("type", "error")
					reply.CreateAttr("from", client.JID())
					reply.CreateAttr("to", v.From)
					reply.CreateAttr("id", v.ID)
					errorReply := reply.CreateElement("error")
					errorReply.CreateAttr("type", "cancel")
					su := errorReply.CreateElement("service-unavailable")
					su.CreateAttr("xmlns", nsXMPPStanzas)
					xmlString, err := root.WriteToString()
					if err == nil {
						_, err = client.SendOrg(xmlString)
						if err != nil {
							log.Println(err)
						}
					}
				}
			case "set":
				root := etree.NewDocument()
				reply := root.CreateElement("iq")
				reply.CreateAttr("type", "error")
				reply.CreateAttr("from", client.JID())
				reply.CreateAttr("to", v.From)
				reply.CreateAttr("id", v.ID)
				errorReply := reply.CreateElement("error")
				errorReply.CreateAttr("type", "cancel")
				su := errorReply.CreateElement("service-unavailable")
				su.CreateAttr("xmlns", nsXMPPStanzas)
				xmlString, err := root.WriteToString()
				if err == nil {
					_, err = client.SendOrg(xmlString)
					if err != nil {
						log.Println(err)
					}
				}
			case "reply", "error":
				iqc <- v
			default:
				iqc <- v
			}
		}
	}
}
