package com.example.models;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * Represents a user account in the system.
 *
 * Demonstrates constructors, builder-like factory methods, Comparable,
 * equals/hashCode, toString, and collection usage.
 */
public class UserAccount implements Comparable<UserAccount> {

    private final long id;
    private final String username;
    private String displayName;
    private String email;
    private Role role;
    private boolean active;
    private final LocalDateTime createdAt;
    private final List<String> permissions;

    public enum Role {
        GUEST, USER, EDITOR, ADMIN;

        public boolean isAtLeast(Role required) {
            return this.ordinal() >= required.ordinal();
        }
    }

    // --- Constructor ---

    public UserAccount(long id, String username, String email) {
        this.id = id;
        this.username = Objects.requireNonNull(username, "username must not be null");
        this.email = Objects.requireNonNull(email, "email must not be null");
        this.displayName = username;
        this.role = Role.USER;
        this.active = true;
        this.createdAt = LocalDateTime.now();
        this.permissions = new ArrayList<>();
    }

    // --- Static factory methods ---

    public static UserAccount createAdmin(long id, String username, String email) {
        UserAccount account = new UserAccount(id, username, email);
        account.role = Role.ADMIN;
        account.permissions.addAll(List.of("read", "write", "delete", "manage_users"));
        return account;
    }

    public static UserAccount createGuest(long id) {
        UserAccount account = new UserAccount(id, "guest_" + id, "guest@example.com");
        account.role = Role.GUEST;
        account.permissions.add("read");
        return account;
    }

    // --- Getters and setters ---

    public long getId()                 { return id; }
    public String getUsername()         { return username; }
    public String getDisplayName()      { return displayName; }
    public String getEmail()            { return email; }
    public Role getRole()               { return role; }
    public boolean isActive()           { return active; }
    public LocalDateTime getCreatedAt() { return createdAt; }

    public List<String> getPermissions() {
        return Collections.unmodifiableList(permissions);
    }

    public void setDisplayName(String displayName) { this.displayName = displayName; }
    public void setEmail(String email)             { this.email = email; }
    public void setRole(Role role)                 { this.role = role; }
    public void setActive(boolean active)          { this.active = active; }

    // --- Permission helpers ---

    public void grantPermission(String permission) {
        if (!permissions.contains(permission)) {
            permissions.add(permission);
        }
    }

    public void revokePermission(String permission) {
        permissions.remove(permission);
    }

    public boolean hasPermission(String permission) {
        return permissions.contains(permission) || role == Role.ADMIN;
    }

    // --- Comparable ---

    @Override
    public int compareTo(UserAccount other) {
        int cmp = this.role.compareTo(other.role);
        return cmp != 0 ? -cmp : this.username.compareToIgnoreCase(other.username);
    }

    // --- equals / hashCode ---

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof UserAccount that)) return false;
        return id == that.id && Objects.equals(username, that.username);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, username);
    }

    // --- toString ---

    @Override
    public String toString() {
        return String.format(
            "UserAccount{id=%d, username='%s', role=%s, active=%s, permissions=%s}",
            id, username, role, active, permissions
        );
    }

    // --- Utility ---

    /**
     * Filters a list of accounts, returning only active users with a minimum role.
     */
    public static List<UserAccount> filterActive(List<UserAccount> accounts, Role minRole) {
        return accounts.stream()
                .filter(UserAccount::isActive)
                .filter(a -> a.getRole().isAtLeast(minRole))
                .sorted()
                .collect(Collectors.toList());
    }
}