package main

import (
	"fmt"
	"image/color"
	"log"

	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/app"
	_ "fyne.io/fyne/v2/canvas"
	"fyne.io/fyne/v2/container"
	"fyne.io/fyne/v2/dialog"
	_ "fyne.io/fyne/v2/layout"
	"fyne.io/fyne/v2/theme"
	"fyne.io/fyne/v2/widget"
	 _ "github.com/mbaklor/fyne-catppuccin"
	 _ "fyne.io/x/fyne/theme"
	"mellium.im/xmpp/jid"
	"mellium.im/xmpp/muc"
	"mellium.im/xmpp/stanza"
	oasisSdk "pain.agency/oasis-sdk"
)

type Message struct {
	Author  string
	Content string
}

var Messages []Message

type myTheme struct{}

func (m myTheme) Color(name fyne.ThemeColorName, variant fyne.ThemeVariant) color.Color {
	return theme.DefaultTheme().Color(name, variant)
}

func (m myTheme) Icon(name fyne.ThemeIconName) fyne.Resource {
	return theme.DefaultTheme().Icon(name)
}

func (m myTheme) Font(style fyne.TextStyle) fyne.Resource {
	return theme.DefaultTheme().Font(style)
}

func (m myTheme) Size(name fyne.ThemeSizeName) float32 {
	if name == theme.SizeNameHeadingText {
		return 18
	}
	return theme.DefaultTheme().Size(name)
}

var scrollDownOnNewMessage bool = true

func addMessageToView() fyne.CanvasObject {
	author := widget.NewLabel("")
	author.TextStyle.Bold = true
	content := widget.NewLabel("")
	content.Wrapping = fyne.TextWrapWord
	return container.NewVBox(author, content)
}

func main() {

	login := oasisSdk.LoginInfo{
		Host:        "sunglocto.net:5222",
		User:        "bot2@sunglocto.net",
		Password:    "iloverobots",
		DisplayName: "bot2",
		TLSoff:      false,
		StartTLS:    true,
		MucsToJoin:  []string{"ringen@muc.isekai.rocks"},
	}

	scroller := widget.NewList(
		func() int {
			return len(Messages)
		}, func() fyne.CanvasObject {
			return addMessageToView()
		}, func(i widget.ListItemID, co fyne.CanvasObject) {
			co.(*fyne.Container).Objects[0].(*widget.Label).SetText(Messages[i].Author)
			co.(*fyne.Container).Objects[1].(*widget.Label).SetText(Messages[i].Content)
		})

	client, err := oasisSdk.CreateClient(
		&login,
		func(client *oasisSdk.XmppClient, msg *oasisSdk.XMPPChatMessage) {
			myMessage := Message{}
			myMessage.Author = msg.From.Resourcepart()
			myMessage.Content = *msg.CleanedBody
			Messages = append(Messages, myMessage)
			if scrollDownOnNewMessage {
				fyne.Do(func() {
					scroller.ScrollToBottom()
				})
			}
		},
		func(client *oasisSdk.XmppClient, _ *muc.Channel, msg *oasisSdk.XMPPChatMessage) {
			myMessage := Message{}
			myMessage.Author = msg.From.Resourcepart()
			myMessage.Content = *msg.CleanedBody
			Messages = append(Messages, myMessage)
			if scrollDownOnNewMessage {
				fyne.Do(func() {
					scroller.ScrollToBottom()
				})
			}
		},
		func(_ *oasisSdk.XmppClient, from jid.JID, state oasisSdk.ChatState) {
			//fromStr := from.String()
			switch state {
			case oasisSdk.ChatStateActive:
			case oasisSdk.ChatStateComposing:
			case oasisSdk.ChatStatePaused:
			case oasisSdk.ChatStateInactive:
			case oasisSdk.ChatStateGone:
			default:
			}
		},
		func(_ *oasisSdk.XmppClient, from jid.JID, id string) {
			fmt.Printf("Delivered %s to %s", id, from.String())
		},
		func(_ *oasisSdk.XmppClient, from jid.JID, id string) {
			fmt.Printf("%s has seen %s", from.String(), id)
		},
	)
	if err != nil {
		log.Fatalln("Could not create client - " + err.Error())
	}

	go func() {
		err = client.Connect()
		if err != nil {
			log.Fatalln("Could not connect - " + err.Error())
		}
	}()


	a := app.New()
	a.Settings().SetTheme(myTheme{})
	w := a.NewWindow("pi")
	w.Resize(fyne.NewSize(500, 500))

	entry := widget.NewMultiLineEntry()
	entry.SetPlaceHolder("Say something, you know you want to.")

	sendbtn := widget.NewButton("Send", func() {
		text := entry.Text
		go func() {
			msg := oasisSdk.XMPPChatMessage{ // TODO: Remove hack when oasisSdk adds message sending (hopefully xd)
				Message: stanza.Message{
					To:   jid.MustParse("ringen@muc.isekai.rocks"), //FIXME
					Type: stanza.GroupChatMessage,                  //FIXME
				},
				ChatMessageBody: oasisSdk.ChatMessageBody{
					Body: &text,
				},
			}
			err := client.Session.Encode(client.Ctx, msg)
			if err != nil {
				dialog.ShowError(err, w)
			}
		}()
		entry.SetText("")
	})

	mit := fyne.NewMenuItem("About pi", func() {
		dialog.ShowInformation("About pi", "the XMPP client from hell\n\npi is an experimental XMPP client\nwritten by Sunglocto in Go.", w)
	})

	mia := fyne.NewMenuItem("Configure message view", func() {
		ch := widget.NewCheck("", func(b bool) {})
		ch.Checked = scrollDownOnNewMessage
		scrollView := widget.NewFormItem("Scroll to bottom on new message", ch)
		items := []*widget.FormItem{
			scrollView,
		}
		dialog.ShowForm("Configure message view", "Apply", "Cancel", items, func(b bool) {
			if b {
				scrollDownOnNewMessage = ch.Checked
			}
		}, w)
	})
	mib := fyne.NewMenuItem("Join a room", func() {
		nick := widget.NewEntry()
		room := widget.NewEntry()
		items := []*widget.FormItem{
			widget.NewFormItem("Nick", nick),
			widget.NewFormItem("MUC address", room),
		}

		dialog.ShowForm("Join a MUC", "Join", "Cancel", items, func(b bool) {
			if b {
				fmt.Println("attempting to join MUC")
				fmt.Println(nick)
				fmt.Println(room)
				go func() {
					client.MucClient.Join(client.Ctx, jid.MustParse(room.Text), client.Session, nil)
				}()
			}
		}, w)
	})
	menu_help := fyne.NewMenu("π", mit)
	menu_changeroom := fyne.NewMenu("β", mib)
	menu_configureview := fyne.NewMenu("γ", mia)
	ma := fyne.NewMainMenu(menu_help, menu_changeroom, menu_configureview)
	w.SetMainMenu(ma)
	tabs := container.NewAppTabs(container.NewTabItem("pi", widget.NewLabel("pi\n\nthe XMPP client from hell")), container.NewTabItem("chat", scroller))
	w.SetContent(container.NewVSplit(tabs, container.NewHSplit(entry, sendbtn))) // TODO: Add send message functionality
	w.ShowAndRun()
}
