<?php
namespace BLR\Backline\Core;

if (!defined('ABSPATH')) { exit; }

/**
 * Centralized access rules for the front-end dashboard and plugin content.
 */
final class Access {
    private const POST_TYPE_CAPS = [
        'blr_contact' => [
            'singular' => 'blr_contact',
            'plural'   => 'blr_contacts',
        ],
        'blr_release' => [
            'singular' => 'blr_release',
            'plural'   => 'blr_releases',
        ],
        'blr_track' => [
            'singular' => 'blr_track',
            'plural'   => 'blr_tracks',
        ],
        'blr_event' => [
            'singular' => 'blr_event',
            'plural'   => 'blr_events',
        ],
        'blr_outreach' => [
            'singular' => 'blr_outreach',
            'plural'   => 'blr_outreach_campaigns',
        ],
        'blr_outreach_log' => [
            'singular' => 'blr_outreach_log',
            'plural'   => 'blr_outreach_logs',
        ],
        'blr_task' => [
            'singular' => 'blr_task',
            'plural'   => 'blr_tasks',
        ],
        'blr_finance_record' => [
            'singular' => 'blr_finance_record',
            'plural'   => 'blr_finance_records',
        ],
    ];

    private const TAXONOMY_CAPS = [
        'blr_release_type' => [
            'manage_terms' => 'manage_blr_release_types',
            'edit_terms'   => 'edit_blr_release_types',
            'delete_terms' => 'delete_blr_release_types',
            'assign_terms' => 'assign_blr_release_types',
        ],
        'blr_release_status' => [
            'manage_terms' => 'manage_blr_release_statuses',
            'edit_terms'   => 'edit_blr_release_statuses',
            'delete_terms' => 'delete_blr_release_statuses',
            'assign_terms' => 'assign_blr_release_statuses',
        ],
    ];

    private const CUSTOM_CAPS = [
        'blr_ba_access',
        'blr_ba_view_dashboard',
        'blr_ba_manage_discography',
        'blr_ba_manage_contacts',
        'blr_ba_manage_outreach',
        'blr_ba_manage_events',
        'blr_ba_manage_tasks',
        'blr_ba_manage_finances',
        'blr_ba_view_notifications',
        'blr_ba_view_settings',
        'blr_ba_edit_settings',
    ];

    public static function boot(): void {
        add_filter('user_has_cap', [self::class, 'grant_plugin_caps_to_allowed_users'], 20, 4);
    }

    /**
     * Admins always have access. Other users must be in the Allowed Users list.
     */
    public static function user_can_access(?int $user_id = null): bool {
        if ($user_id === null) {
            $user_id = get_current_user_id();
        }

        $user = get_userdata((int) $user_id);
        return self::user_has_dashboard_access($user);
    }

    public static function user_has_dashboard_access($user): bool {
        if (!$user instanceof \WP_User || !$user->exists()) {
            return false;
        }

        if (!empty($user->allcaps['manage_options']) || in_array('administrator', (array) $user->roles, true)) {
            return true;
        }

        $allowed = SettingsPage::get_allowed_user_ids();
        return in_array((int) $user->ID, $allowed, true);
    }

    public static function grant_plugin_caps_to_allowed_users(array $allcaps, array $caps, array $args, $user): array {
        if (!$user instanceof \WP_User || !$user->exists()) {
            return $allcaps;
        }

        if (!empty($user->allcaps['manage_options']) || in_array('administrator', (array) $user->roles, true)) {
            foreach (self::all_plugin_caps() as $cap) {
                $allcaps[$cap] = true;
            }

            return $allcaps;
        }

        if (!self::user_has_dashboard_access($user)) {
            return $allcaps;
        }

        $granted_caps = SettingsPage::allowed_operator_caps((int) $user->ID);

        foreach ($granted_caps as $cap) {
            $allcaps[$cap] = true;
        }

        if (!empty($allcaps['blr_ba_view_dashboard'])) {
            $allcaps['blr_ba_access'] = true;
        }

        return $allcaps;
    }


    private static function post_type_caps_map(): array {
        $caps = apply_filters('blr_backline_post_type_caps', self::POST_TYPE_CAPS);
        return is_array($caps) ? $caps : self::POST_TYPE_CAPS;
    }

    private static function taxonomy_caps_map(): array {
        $caps = apply_filters('blr_backline_taxonomy_caps', self::TAXONOMY_CAPS);
        return is_array($caps) ? $caps : self::TAXONOMY_CAPS;
    }

    public static function grant_administrator_caps(): void {
        $role = get_role('administrator');
        if (!$role) {
            return;
        }

        foreach (self::all_plugin_caps() as $cap) {
            $role->add_cap($cap);
        }
    }

    public static function all_plugin_caps(): array {
        $caps = [];

        foreach (array_keys(self::post_type_caps_map()) as $post_type) {
            $caps = array_merge($caps, array_values(self::post_type_capabilities($post_type)));
        }

        foreach (self::taxonomy_caps_map() as $taxonomy_caps) {
            $caps = array_merge($caps, array_values($taxonomy_caps));
        }

        $caps = array_merge($caps, self::CUSTOM_CAPS);

        return array_values(array_unique($caps));
    }

    public static function post_type_registration_args(string $post_type): array {
        return [
            'capability_type' => self::post_type_capability_type($post_type),
            'capabilities'    => self::post_type_capabilities($post_type),
            'map_meta_cap'    => true,
        ];
    }

    public static function taxonomy_registration_args(string $taxonomy): array {
        return [
            'capabilities' => self::taxonomy_capabilities($taxonomy),
        ];
    }

    public static function post_type_capability_type(string $post_type): array {
        $def = self::post_type_caps_map()[$post_type] ?? null;
        if (!$def) {
            return ['post', 'posts'];
        }

        return [$def['singular'], $def['plural']];
    }

    public static function post_type_capabilities(string $post_type): array {
        $def = self::post_type_caps_map()[$post_type] ?? null;
        if (!$def) {
            return [];
        }

        $singular = $def['singular'];
        $plural = $def['plural'];

        return [
            'edit_post'              => 'edit_' . $singular,
            'read_post'              => 'read_' . $singular,
            'delete_post'            => 'delete_' . $singular,
            'edit_posts'             => 'edit_' . $plural,
            'edit_others_posts'      => 'edit_others_' . $plural,
            'publish_posts'          => 'publish_' . $plural,
            'read_private_posts'     => 'read_private_' . $plural,
            'read'                   => 'read',
            'delete_posts'           => 'delete_' . $plural,
            'delete_private_posts'   => 'delete_private_' . $plural,
            'delete_published_posts' => 'delete_published_' . $plural,
            'delete_others_posts'    => 'delete_others_' . $plural,
            'edit_private_posts'     => 'edit_private_' . $plural,
            'edit_published_posts'   => 'edit_published_' . $plural,
            'create_posts'           => 'create_' . $plural,
        ];
    }

    public static function taxonomy_capabilities(string $taxonomy): array {
        return self::taxonomy_caps_map()[$taxonomy] ?? [];
    }

    public static function can_create_post_type(string $post_type): bool {
        $caps = self::post_type_capabilities($post_type);
        if (empty($caps['create_posts'])) {
            return false;
        }

        return current_user_can($caps['create_posts']);
    }

    public static function can_manage_post_type(string $post_type): bool {
        $caps = self::post_type_capabilities($post_type);
        if (empty($caps['edit_posts'])) {
            return false;
        }

        return current_user_can($caps['edit_posts']);
    }

    public static function can_edit_post($post, string $expected_post_type = ''): bool {
        $post = get_post($post);
        if (!$post instanceof \WP_Post) {
            return false;
        }

        if ($expected_post_type !== '' && $post->post_type !== $expected_post_type) {
            return false;
        }

        return current_user_can('edit_post', (int) $post->ID);
    }

    public static function can_delete_post($post, string $expected_post_type = ''): bool {
        $post = get_post($post);
        if (!$post instanceof \WP_Post) {
            return false;
        }

        if ($expected_post_type !== '' && $post->post_type !== $expected_post_type) {
            return false;
        }

        return current_user_can('delete_post', (int) $post->ID);
    }

    public static function can_manage_taxonomy(string $taxonomy): bool {
        $caps = self::taxonomy_capabilities($taxonomy);
        if (empty($caps['manage_terms'])) {
            return false;
        }

        return current_user_can($caps['manage_terms']);
    }

    public static function current_user_can_custom(string $cap): bool {
        return current_user_can($cap);
    }

    public static function module_manage_cap(string $module): string {
        $map = SettingsPage::module_capability_map();
        return isset($map[$module]) ? (string) $map[$module] : 'blr_ba_access';
    }

    public static function module_is_accessible(string $module): bool {
        if (!SettingsPage::is_module_enabled($module)) {
            return false;
        }

        $cap = self::module_manage_cap($module);
        return current_user_can($cap);
    }

    public static function rest_meta_auth_callback(string $expected_post_type): callable {
        return static function($allowed, $meta_key = '', $object_id = 0) use ($expected_post_type): bool {
            $object_id = absint($object_id);
            if ($object_id <= 0) {
                return Access::can_manage_post_type($expected_post_type);
            }

            return Access::can_edit_post($object_id, $expected_post_type);
        };
    }
}
