package fr.univ.lyon1.server;

import fr.univ.lyon1.common.Message;
import fr.univ.lyon1.common.User;
import fr.univ.lyon1.server.models.UserChannelModel;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

public class Server {
    private final int port;
    private List<ConnectedClient> clients = new ArrayList<>();
    private static User serverUser = new User(UUID.fromString("3539b6bf-5eb3-41d4-893f-cbf0caa9ca74"), "server");

    Server(int port) throws IOException {
        this.port = port;
        Database.getDatabase();
        Thread connection = new Thread(new Connection(this));
        connection.start();
    }

    public ConnectedClient addClient(ConnectedClient newClient) {
        clients.add(newClient);
        return newClient;
    }

    public int broadcastMessage(Message message, int id) {
        List<UUID> users = UserChannelModel.getUsers(message.getChannel()).stream().map(User::getUUID).toList();
        for (ConnectedClient client : clients.stream().filter(connectedClient -> users.contains(connectedClient.getUser().getUUID())).toList()) {
            if (id == -1 || client.getId() != id)
                try {
                    client.sendMessage(message);
                } catch (IOException e) {
                    System.err.println("Fail to send message to " + client.getId());
                    e.printStackTrace();
                }
        }
        return id;
    }

    public ConnectedClient disconnectedClient(ConnectedClient client) {
        try {
            client.closeClient();
        } catch (IOException e) {
            System.err.println("Fail to close client "+client.getId());
            e.printStackTrace();
        }

        clients.remove(client);

        System.out.println("Client "+client.getId()+" disconnected");
        return client;
    }

    public int getPort() {
        return port;
    }

    public static User getServerUser() {
        return serverUser;
    }

    public List<User> getUsers() {
        return clients.stream().map(ConnectedClient::getUser).toList();
    }
}