<?php

declare(strict_types=1);

namespace Instinctor\Core;


if (!defined('ABSPATH')) exit;
use Instinctor\Core\Auth;
use Instinctor\Core\Auth\StandaloneDriver;
use Instinctor\Core\DB;

/**
 * RoleManager — per-user workspace access control, dual-mode.
 *
 * WordPress mode:  individual instinctor_* capabilities per user.
 * Standalone mode: instinctor_users table with owner/admin/manager/agent roles
 *                  (migrating to per-user caps in future).
 *
 * Workspace capabilities:
 *   instinctor_chat     → Relay workspace
 *   instinctor_store    → Store workspace
 *   instinctor_impulse  → Impulse workspace
 *   instinctor_seo      → SEO workspace
 *   instinctor_settings → Settings workspace
 *
 * Administrators (manage_options) always have full access.
 *
 * @since 3.0.0
 * @updated 3.23.217 — per-user workspace checkboxes, roles removed
 */
class RoleManager
{
    private static ?RoleManager $instance = null;

    /** All Instinctor capabilities */
    public const CAPABILITIES = [
        'instinctor_access',
        'instinctor_chat',
        'instinctor_chat_settings',
        'instinctor_store',
        'instinctor_impulse',
        'instinctor_seo',
        'instinctor_settings',
    ];

    /** Capability required per workspace */
    public const WORKSPACE_CAPS = [
        'chat'     => 'instinctor_chat',
        'store'    => 'instinctor_store',
        'impulse'  => 'instinctor_impulse',
        'seo'      => 'instinctor_seo',
        'settings' => 'instinctor_settings',
    ];

    /** Human-readable workspace labels for team UI */
    public const WORKSPACE_LABELS = [
        'chat'     => 'Relay',
        'store'    => 'Store',
        'impulse'  => 'Impulse',
        'seo'      => 'SEO',
        'settings' => 'Settings',
    ];


    public static function instance(): self
    {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    private static function isStandalone(): bool
    {
        return Plugin::isStandalone();
    }

    // ── WordPress mode — cap registration ──────────────────────────────────

    public static function install(): void
    {
        if (self::isStandalone()) return;

        $admin = get_role('administrator');
        if ($admin) {
            foreach (self::CAPABILITIES as $cap) {
                $admin->add_cap($cap, true);
            }
        }

    }

    public static function uninstall(): void
    {
        if (self::isStandalone()) return;

        $admin = get_role('administrator');
        if ($admin) {
            foreach (self::CAPABILITIES as $cap) {
                $admin->remove_cap($cap);
            }
        }
    }

    // ── Access checks (both modes) ────────────────────────────────────────

    public function canAccessWorkspace(string $workspace): bool
    {
        if (Auth::can('manage_options')) return true;

        $cap = self::WORKSPACE_CAPS[$workspace] ?? null;
        if (!$cap) return false;

        return Auth::can($cap);
    }

    public function canManageChatSettings(): bool
    {
        return Auth::can('manage_options') || Auth::can('instinctor_chat_settings');
    }

    public function getAccessibleWorkspaces(): array
    {
        $workspaces = [];
        foreach (self::WORKSPACE_CAPS as $ws => $cap) {
            if ($this->canAccessWorkspace($ws)) {
                $workspaces[] = $ws;
            }
        }
        return $workspaces;
    }

    public function getMenuCapability(): string
    {
        return 'instinctor_access';
    }

    // ── Team management — dual-mode ───────────────────────────────────────

    public function getTeamMembers(): array
    {
        if (self::isStandalone()) {
            return $this->getTeamStandalone();
        }
        return $this->getTeamWordPress();
    }

    private function getTeamStandalone(): array
    {
        $prefix = DB::prefix();
        $table  = $prefix . 'instinctor_users';
        // Team = internal STAFF only. ADMIN_ROLES includes 'site_owner' because a
        // tenant has admin access to their OWN site, but tenants are customers, not
        // team members — listing them here floods the Team panel with every free
        // site owner (and would be millions at scale). Exclude tenant roles.
        $staffRoles = array_values(array_diff(StandaloneDriver::ADMIN_ROLES, ['site_owner']));
        $roles      = implode("','", array_map('addslashes', $staffRoles));

        $rows = DB::get_results(
            "SELECT id, email, display_name, role, status, last_active
             FROM `{$table}`
             WHERE role IN ('{$roles}')
             ORDER BY FIELD(role,'owner','admin','manager','agent'), display_name ASC",
            'ARRAY_A'
        );

        return array_map(function ($r) {
            return [
                'id'           => (int) $r['id'],
                'display_name' => $r['display_name'],
                'email'        => $r['email'],
                'workspaces'   => $this->standaloneRoleToWorkspaces($r['role']),
                'status'       => $r['status'] ?? 'active',
                'last_active'  => $r['last_active'] ?? null,
                'is_owner'     => $r['role'] === 'owner',
            ];
        }, $rows ?: []);
    }

    private function standaloneRoleToWorkspaces(string $role): array
    {
        return match ($role) {
            'owner', 'admin' => array_keys(self::WORKSPACE_CAPS),
            'manager'        => ['chat', 'store'],
            'agent'          => ['chat'],
            default          => [],
        };
    }

    private function getTeamWordPress(): array
    {
        if (!function_exists('get_users')) return [];

        $allUsers = get_users(['fields' => 'all_with_meta']);
        $result   = [];

        foreach ($allUsers as $user) {
            $isAdmin = in_array('administrator', (array) $user->roles, true);
            $hasAccess = $user->has_cap('instinctor_access');
            if (!$isAdmin && !$hasAccess) continue;

            $workspaces = [];
            if ($isAdmin) {
                $workspaces = array_keys(self::WORKSPACE_CAPS);
            } else {
                foreach (self::WORKSPACE_CAPS as $ws => $cap) {
                    if ($user->has_cap($cap)) {
                        $workspaces[] = $ws;
                    }
                }
            }

            $result[] = [
                'id'           => (int) $user->ID,
                'display_name' => $user->display_name,
                'email'        => $user->user_email,
                'workspaces'   => $workspaces,
                'status'       => 'active',
                'last_active'  => null,
                'is_owner'     => $isAdmin,
            ];
        }
        return $result;
    }

    /**
     * Set workspace access for a team member.
     *
     * @param int $userId
     * @param string[] $workspaces e.g. ['chat', 'store', 'seo']
     */
    public function setTeamMemberAccess(int $userId, array $workspaces): bool
    {
        if (self::isStandalone()) {
            return $this->setAccessStandalone($userId, $workspaces);
        }
        return $this->setAccessWordPress($userId, $workspaces);
    }

    private function setAccessWordPress(int $userId, array $workspaces): bool
    {
        if (!function_exists('get_userdata')) return false;

        $user = get_userdata($userId);
        if (!$user) return false;
        if (in_array('administrator', (array) $user->roles, true)) return false;

        // Remove all instinctor caps
        foreach (self::CAPABILITIES as $cap) {
            $user->remove_cap($cap);
        }

        $valid   = array_keys(self::WORKSPACE_CAPS);
        $granted = array_intersect($workspaces, $valid);

        if (!empty($granted)) {
            $user->add_cap('instinctor_access', true);
            foreach ($granted as $ws) {
                $user->add_cap(self::WORKSPACE_CAPS[$ws], true);
            }
            if (in_array('settings', $granted, true)) {
                $user->add_cap('instinctor_chat_settings', true);
            }
            if (!$user->has_cap('read')) {
                $user->add_cap('read', true);
            }
        }

        return true;
    }

    private function setAccessStandalone(int $userId, array $workspaces): bool
    {
        $table = DB::prefix() . 'instinctor_users';
        $current = DB::get_var(DB::prepare("SELECT role FROM `{$table}` WHERE id = %d", $userId));
        if ($current === 'owner') return false;

        $granted = array_intersect($workspaces, array_keys(self::WORKSPACE_CAPS));

        if (count($granted) === count(self::WORKSPACE_CAPS)) {
            $role = 'admin';
        } elseif (in_array('store', $granted, true)) {
            $role = 'manager';
        } elseif (in_array('chat', $granted, true)) {
            $role = 'agent';
        } else {
            $role = 'agent';
        }

        DB::update($table, ['role' => $role], ['id' => $userId]);
        return true;
    }

    public function setTeamMemberRole(int $userId, string $role): bool
    {
        $workspaces = match ($role) {
            'admin', 'administrator' => array_keys(self::WORKSPACE_CAPS),
            'manager' => ['chat', 'store'],
            'agent'   => ['chat'],
            'none'    => [],
            default   => [],
        };
        return $this->setTeamMemberAccess($userId, $workspaces);
    }

    /** Returns workspace labels for UI */
    public function getAssignableRoles(): array
    {
        return self::WORKSPACE_LABELS;
    }

    public function updateTeamMember(int $userId, array $data): bool
    {
        $update = [];
        if (isset($data['display_name'])) {
            $name = trim((string) $data['display_name']);
            if ($name !== '') $update['display_name'] = $name;
        }
        if (isset($data['email'])) {
            $email = sanitize_email($data['email']);
            if ($email !== '') $update['email'] = $email;
        }
        if (empty($update)) return true;

        // Option A (2026-07-05): team members are the plugin's OWN
        // instinctor_users on WordPress + standalone alike — no wp_update_user.
        // The WP site's users are never touched.
        $table   = DB::prefix() . 'instinctor_users';
        $current = DB::get_var(DB::prepare("SELECT role FROM `{$table}` WHERE id = %d", $userId));
        if ($current === null) return false;
        DB::update($table, $update, ['id' => $userId]);
        return true;
    }

    public function revokeAccess(int $userId): bool
    {
        if (self::isStandalone()) {
            $table = DB::prefix() . 'instinctor_users';
            $current = DB::get_var(DB::prepare("SELECT role FROM `{$table}` WHERE id = %d", $userId));
            if ($current === 'owner') return false;
            DB::update($table, ['status' => 'suspended'], ['id' => $userId]);
            return true;
        }
        return $this->setTeamMemberAccess($userId, []);
    }

    public function getInstinctorUsers(): array
    {
        return $this->getTeamWordPress();
    }
}
