// Written by retoor@molodetz.nl

// This class defines a custom HTML element that displays a list of messages with avatars and timestamps. It handles message addition with a delay in event dispatch and ensures the display of messages in the correct format.

// The code seems to rely on some external dependencies like 'models.Message', 'app', and 'Schedule'. These should be imported or defined elsewhere in your application.

// MIT License: This is free software. Permission is granted to use, copy, modify, and/or distribute this software for any purpose with or without fee. The software is provided "as is" without any warranty.

class MessageListElement extends HTMLElement {
    static get observedAttributes() {
        return ["messages"];
    }

    messages = [];
    room = null;
    url = null;
    container = null;
    messageEventSchedule = null;
    observer = null;

    constructor() {
        super();
        this.attachShadow({ mode: 'open' });
        this.component = document.createElement('div');
        this.shadowRoot.appendChild(this.component);
    }

    linkifyText(text) {
        const urlRegex = /https?:\/\/[^\s]+/g;
        return text.replace(urlRegex, (url) => `<a href="${url}" target="_blank" rel="noopener noreferrer">${url}</a>`);
    }

    timeAgo(date1, date2) {
        const diffMs = Math.abs(date2 - date1);
        const days = Math.floor(diffMs / (1000 * 60 * 60 * 24));
        const hours = Math.floor((diffMs % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
        const minutes = Math.floor((diffMs % (1000 * 60 * 60)) / (1000 * 60));
        const seconds = Math.floor((diffMs % (1000 * 60)) / 1000);

        if (days) {
            return `${days} ${days > 1 ? 'days' : 'day'} ago`;
        }
        if (hours) {
            return `${hours} ${hours > 1 ? 'hours' : 'hour'} ago`;
        }
        if (minutes) {
            return `${minutes} ${minutes > 1 ? 'minutes' : 'minute'} ago`;
        }
        return 'just now';
    }

    timeDescription(isoDate) {
        const date = new Date(isoDate);
        const hours = String(date.getHours()).padStart(2, "0");
        const minutes = String(date.getMinutes()).padStart(2, "0");
        let timeStr = `${hours}:${minutes}, ${this.timeAgo(new Date(isoDate), Date.now())}`;
        return timeStr;
    }

    createElement(message) {
        const element = document.createElement("div");
        element.dataset.uid = message.uid;
        element.dataset.color = message.color;
        element.dataset.channel_uid = message.channel_uid;
        element.dataset.user_nick = message.user_nick;
        element.dataset.created_at = message.created_at;
        element.dataset.user_uid = message.user_uid;
        element.dataset.message = message.message;

        element.classList.add("message");
        if (!this.messages.length || this.messages[this.messages.length - 1].user_uid != message.user_uid) {
            element.classList.add("switch-user");
        }

        const avatar = document.createElement("div");
        avatar.classList.add("avatar");
        avatar.classList.add("no-select");
        avatar.style.backgroundColor = message.color;
        avatar.style.color = "black";
        avatar.innerText = message.user_nick[0];

        const messageContent = document.createElement("div");
        messageContent.classList.add("message-content");

        const author = document.createElement("div");
        author.classList.add("author");
        author.style.color = message.color;
        author.textContent = message.user_nick;

        const text = document.createElement("div");
        text.classList.add("text");
        if (message.html) text.innerHTML = message.html;

        const time = document.createElement("div");
        time.classList.add("time");
        time.dataset.created_at = message.created_at;
        time.textContent = this.timeDescription(message.created_at);

        messageContent.appendChild(author);
        messageContent.appendChild(text);
        messageContent.appendChild(time);

        element.appendChild(avatar);
        element.appendChild(messageContent);

        message.element = element;

        return element;
    }

    addMessage(message) {
        const obj = new models.Message(
            message.uid,
            message.channel_uid,
            message.user_uid,
            message.user_nick,
            message.color,
            message.message,
            message.html,
            message.created_at,
            message.updated_at
        );

        const element = this.createElement(obj);
        this.messages.push(obj);
        this.container.appendChild(element);

        this.messageEventSchedule.delay(() => {
            this.dispatchEvent(new CustomEvent("message", { detail: obj, bubbles: true }));
        });

        return obj;
    }

    scrollBottom() {
        this.container.scrollTop = this.container.scrollHeight;
    }

    connectedCallback() {
        const link = document.createElement('link');
        link.rel = 'stylesheet';
        link.href = '/base.css';
        this.component.appendChild(link);
        this.component.classList.add("chat-messages");

        this.container = document.createElement('div');
        this.component.appendChild(this.container);

        this.messageEventSchedule = new Schedule(500);
        this.messages = [];
        this.channel_uid = this.getAttribute("channel");

        app.addEventListener(this.channel_uid, (data) => {
            this.addMessage(data);
        });

        this.dispatchEvent(new CustomEvent("rendered", { detail: this, bubbles: true }));

        this.timeUpdateInterval = setInterval(() => {
            this.messages.forEach((message) => {
                const newText = this.timeDescription(message.created_at);
                if (newText != message.element.innerText) {
                    message.element.querySelector(".time").innerText = newText;
                }
            });
        }, 30000);
    }
}

customElements.define('message-list', MessageListElement);
