<?php

namespace RtmBusiness\PostSync\Rest;

use RtmBusiness\PostSync\Logger;
use RtmBusiness\PostSync\SyncController;
use WordpressModels\Rest\AbstractRestApi;
use WordpressModels\Rest\Attribute\RestRoute;
use WP_Error;
use WP_Http;
use WP_REST_Request;
use WP_REST_Response;

class SettingsApi extends AbstractRestApi
{

    private SyncController $syncController;

    public function __construct()
    {
        $this->syncController = SyncController::instance();
        parent::__construct('postsync');
    }

    #[RestRoute(
        'fetchMetaFieldsForPostType',
        ['GET'],
        'is_authorized()',
        arguments: [
            'post_type' => [
                'required' => true,
                'type' => 'string',
            ]
        ],
        public: false
    )]
    public function fetchMetaFieldsForPostType(WP_REST_Request $request): WP_Error|WP_REST_Response
    {
        // Check if the post_type parameter is set
        $post_type = $request->get_param('post_type');
        if (!$post_type) {
            return new WP_Error('missing_post_type', 'Missing post_type parameter', ['status' => 400]);
        }

        // Fetch the meta fields for the post type
        $meta_fields = $this->getMetaFieldsForPostType($post_type);
        $excluded_meta_fields = get_site_option("postsync_" . $post_type . "_excluded_meta_fields", []);

        $meta_fields = array_values(array_diff($meta_fields, $excluded_meta_fields));


        // Return the meta fields as a JSON array
        return new WP_REST_Response($meta_fields, WP_Http::OK);
    }

    #[RestRoute(
        'fetchExcludedMetaFieldsForPostType',
        ['GET'],
        'is_authorized()',
        arguments: [
            'post_type' => [
                'required' => true,
                'type' => 'string',
            ]
        ],
        public: false
    )]
    public function fetchExcludedMetaFieldsForPostType(WP_REST_Request $request): WP_Error|WP_REST_Response
    {
        // Check if the post_type parameter is set
        $post_type = $request->get_param('post_type');
        if (!$post_type) {
            return new WP_Error('missing_post_type', 'Missing post_type parameter', ['status' => 400]);
        }

        // Fetch the excluded meta fields for the post type
        $excluded_meta_fields = get_site_option("postsync_" . $post_type . "_excluded_meta_fields", []);

        // Return the meta fields as a JSON array
        return new WP_REST_Response($excluded_meta_fields, WP_Http::OK);
    }

    #[RestRoute(
        'settings',
        ['PATCH'],
        "role('administrator')",
        arguments: [
            'resync' => [
                'required' => true,
                'type' => 'bool',
            ],
            'sync_metadata' => [
                'required' => true,
                'type' => 'bool',
            ],
            'sync_taxonomies' => [
                'required' => true,
                'type' => 'bool',
            ],
            'copy_media' => [
                'required' => true,
                'type' => 'bool',
            ],
            'excluded_meta_fields' => [
                'required' => true,
                'type' => 'object',
            ]
        ],
        public: false
    )]
    public function saveSettings(WP_REST_Request $request): WP_Error|WP_REST_Response
    {
        if (!isset($request['resync'])) {
            return new WP_Error('no_resync_flag', 'No resync flag', ['status' => 400]);
        }
        $json_params = $request->get_json_params();

        $enabledPostTypes = $json_params['enabled_post_types'];

        update_site_option('postsync_enabled_post_types', $enabledPostTypes);

        $excluded_meta = $json_params['excluded_meta_fields'];

        foreach ($excluded_meta as $post_type => $excluded_fields) {
            update_site_option("postsync_" . $post_type . "_excluded_meta_fields", $excluded_fields);
        }

        $sync_metadata = isset($json_params['sync_metadata']) && $json_params['sync_metadata'] === true;
        update_site_option('postsync_sync_metadata', $sync_metadata);

        $sync_taxonomies = isset($json_params['sync_taxonomies']) && $json_params['sync_taxonomies'] === true;
        update_site_option('postsync_sync_taxonomies', $sync_taxonomies);

        $copy_media = isset($json_params['copy_media']) && $json_params['copy_media'] === true;
        update_site_option('postsync_copy_media', $copy_media);

        $resync = isset($json_params['resync']) && $json_params['resync'] === true;

        if ($resync) {
            $this->syncController->resyncPosts();
        }
        return new WP_REST_Response(['success' => true], WP_Http::OK);
    }

    #[RestRoute(
        'disconnectChild',
        ['POST'],
        'is_authorized()',
        arguments: [
            'child_post_id' => [
                'required' => true,
                'type' => 'int',
            ],
        ],
        public: false
    )]
    public function disconnectChild(WP_REST_Request $request): WP_Error|WP_REST_Response
    {
        if (!isset($request['child_post_id'])) {
            return new WP_Error('no_child_post_id', 'No child post id', ['status' => 400]);
        }

        $json_params = $request->get_json_params();

        $childPostId = $json_params['child_post_id'];
        $data = $this->syncController->getSyncDataWithChild('post', get_current_blog_id(), $childPostId);

        if (!current_user_can('postsync_can_disconnect') || !current_user_can_for_blog($data->parentBlogId, 'postsync_can_disconnect')) {
            return new WP_REST_Response(['success' => false, 'message' => 'You do not have permission to disconnect from the parent site'], WP_Http::OK);
        }

        $data->removeChild($childPostId);
        $this->syncController->updateSyncData($data);
        Logger::info("Disconnected from parent", "Child site disconnected from parent successfully", "SettingsApi", "sync", ['fromBlog' => get_current_blog_id(), 'remainingChildren' => json_encode($data->getLinkedChildren(), true)]);


        return new WP_REST_Response(['success' => true], WP_Http::OK);
    }

    #[RestRoute(
        'deleteChildPost',
        ['POST'],
        'is_authorized()',
        arguments: [
            'child_blog_id' => [
                'required' => true,
                'type' => 'int',
            ],
            'child_post_id' => [
                'required' => true,
                'type' => 'int',
            ],
        ],
        public: false
    )]
    public function deleteChildPost(WP_REST_Request $request): WP_Error|WP_REST_Response
    {
        if (!isset($request['child_post_id'])) {
            return new WP_Error('no_child_post_id', 'No child post id', ['status' => 400]);
        }
        if (!isset($request['child_blog_id'])) {
            return new WP_Error('no_child_blog_id', 'No child blog id', ['status' => 400]);
        }

        $json_params = $request->get_json_params();

        $childPostId = $json_params['child_post_id'];
        $childBlogId = $json_params['child_blog_id'];

        if (!current_user_can_for_blog($childBlogId, 'postsync_can_trashrestore')) {
            return new WP_REST_Response(['success' => false, 'message' => 'You do not have permission to delete a child post on that blog.'], WP_Http::OK);
        }

        $this->syncController->deletePost($childBlogId, $childPostId);
        Logger::info("Deleted child post", "Child post succcesfully deleted", "SettingsApi", "sync", ['fromBlog' => get_current_blog_id(), 'deleted' => ['blogId' => $childBlogId, 'postId' => $childPostId]]);


        return new WP_REST_Response(['success' => true], WP_Http::OK);
    }

    #[RestRoute(
        'permissions',
        ['PATCH'],
        "role('administrator')",
        arguments: [],
        public: false
    )]
    public function updateUserSyncPermissions(WP_REST_Request $request): WP_Error|WP_REST_Response
    {
        // Getting raw data from request
        $json = $request->get_body();
        // Converting JSON into associative array
        $data = json_decode($json, true);

        if (!$data) {
            return new WP_Error('invalid_data', 'No valid data provided', ['status' => 400]);
        }

        // List of all possible capabilities
        $allCapabilities = ['postsync_can_publish', 'postsync_can_disconnect', 'postsync_can_trashrestore', 'postsync_can_permdelete'];

        foreach ($data as $blogId => $userCapabilities) {
            switch_to_blog($blogId);

            foreach ($userCapabilities as $username => $capabilities) {
                $user = get_user_by('login', $username);
                // Get user by username
                if (!$user) {
                    return new WP_Error('invalid_user', 'Invalid user ' . $username, ['status' => 400]);
                }

                foreach ($allCapabilities as $capability) {
                    if (in_array($capability, $capabilities)) {
                        // If the capability is in the list of selected capabilities, add it
                        $user->add_cap($capability);
                    } else {
                        // If the capability is not in the list of selected capabilities, remove it
                        $user->remove_cap($capability);
                    }
                }
            }

            restore_current_blog();
        }

        return new WP_REST_Response(['success' => true], WP_Http::OK);
    }


    #[RestRoute(
        'fetchMetaboxData',
        ['GET'],
        'is_authorized()',
        arguments: [
            'child_post_id' => [
                'required' => true,
                'type' => 'int',
            ],
        ],
        public: false
    )]
    public function fetchMetaboxData(WP_REST_Request $request): WP_Error|WP_REST_Response
    {
        if (!isset($request['child_post_id'])) {
            return new WP_Error('no_child_post_id', 'No child post id', ['status' => 400]);
        }
        $postId = $request->get_param('child_post_id');

        $jsonResponse = [];
        $jsonResponse['options']['overwriteSiteIds'] = [];


        $currentBlogId = get_current_blog_id();

        //Check if we are child of a post relation
        $parentRelation = $this->syncController->getSyncDataWithChild('post', $currentBlogId, $postId);

        //If the current post being editted has a parent -> Show disconnect option
        if ($parentRelation !== null) {
            $blog_details = get_blog_details($parentRelation->parentBlogId);
            $site_url = $blog_details->siteurl;
            $site_name = $blog_details->blogname;
            $can_disconnect = current_user_can('postsync_can_disconnect') && current_user_can_for_blog($parentRelation->parentBlogId, 'postsync_can_disconnect');


            $jsonResponse['parentBlog'] = [
                'site_url' => esc_html($site_url),
                'site_name' => esc_html($site_name),
                'parent_post_id' => $parentRelation->parentPostId,
                'child_post_id' => $postId,
                'can_disconnect' => $can_disconnect
            ];

            //Display other blogs which are linked to the parent post
            if (!empty($parentRelation->getLinkedChildren())) {
                $blogIds = array_map(function ($item) {
                    return $item->blogId;
                }, $parentRelation->getLinkedChildren());

                foreach ($blogIds as $blogId) {
                    if ($blogId === $currentBlogId) {
                        continue;
                    }
                    $blog_details = get_blog_details($blogId);
                    $site_url = $blog_details->siteurl;
                    $site_name = $blog_details->blogname;

                    $jsonResponse['linkedBlogs'][] = [
                        'site_name' => esc_html($site_name),
                        'site_url' => esc_html($site_url),
                    ];
                }
            }
        }

        //Check if we are parent of a post relation
        $data = $this->syncController->getSyncData('post', get_current_blog_id(), $postId);

        $excludedSites = [$currentBlogId];
        if ($parentRelation !== null) {
            $excludedSites[] = $parentRelation->parentBlogId;
            $blogIds = array_map(function ($item) {
                return $item->blogId;
            }, $parentRelation->getLinkedChildren());

            $excludedSites = array_merge($excludedSites, $blogIds);
        }

        $sites = get_sites(['site__not_in' => $excludedSites]);


        //Show checkboxes for sites eligible for a new sync relation
        if (!empty($sites)) {
            $can_publish_current = current_user_can('postsync_can_publish');
            $can_trashrestore_current = current_user_can('postsync_can_trashrestore');

            foreach ($sites as $site) {
                $blog_details = get_blog_details($site->blog_id);
                $site_url = $blog_details->siteurl;
                $site_name = $blog_details->blogname;
                $site_id = $site->blog_id;
                $can_publish = (current_user_can_for_blog($site_id, 'postsync_can_publish') && $can_publish_current);
                $can_trashrestore = (current_user_can_for_blog($site_id, 'postsync_can_trashrestore') && $can_trashrestore_current);

                //if there is a sync relation with a child post, and then post is in the trash, disable delete option
                $child = $data->getLinkedChild($site->blog_id);
                if ($child !== null) {
                    if ($child->getDeletedOn() !== null) {
                        $can_trashrestore = false;
                    }
                    if ($child->isOverwriteSlug()) {
                        $jsonResponse['options']['overwriteSiteIds'][] = $site->blog_id;
                    }
                }

                $jsonResponse['eligibleSites'][] = [
                    'site_id' => esc_attr($site_id),
                    'checked' => $data->isLinkedToChildBlog($site->blog_id),
                    'child_post_id' => $data->getLinkedPostId($site->blog_id),
                    'site_name' => esc_html($site_name),
                    'site_url' => esc_html($site_url),
                    'can_publish' => $can_publish,
                    'can_trashrestore' => $can_trashrestore
                ];
            }
        }


        return new WP_REST_Response($jsonResponse, WP_Http::OK);
    }


    /**
     * Retrieves the unique meta field keys for a specific post type
     *
     * @param string $postType
     * @return array
     */
    public function getMetaFieldsForPostType(string $postType): array
    {
        global $wpdb;

        $sql = "
        SELECT DISTINCT pm.meta_key
        FROM $wpdb->postmeta pm
        JOIN $wpdb->posts p ON p.ID = pm.post_id
        WHERE p.post_type = %s
    ";

        $prepared_sql = $wpdb->prepare($sql, $postType);

        return $wpdb->get_col($prepared_sql);
    }
}
