<?php

namespace Give\API\REST\V3\Routes\Campaigns;

use Exception;
use Give\API\REST\V3\Routes\Campaigns\Permissions\CampaignPermissions;
use Give\API\REST\V3\Routes\Campaigns\ValueObjects\CampaignRoute;
use Give\Campaigns\CampaignDonationQuery;
use Give\Campaigns\Models\Campaign;
use Give\Donations\ValueObjects\DonationMetaKeys;
use Give\Framework\Permissions\Facades\UserPermissions;
use WP_Error;
use WP_REST_Controller;
use WP_REST_Response;
use WP_REST_Server;

class CampaignCommentsController extends WP_REST_Controller
{
    /**
     * @var string
     */
    protected $namespace;

    public function __construct()
    {
        $this->namespace = CampaignRoute::NAMESPACE;
    }

    /**
     * @since 4.13.0 add schema
     * @since 4.0.0
     */
    public function register_routes()
    {
        register_rest_route(
            $this->namespace,
            '/' . CampaignRoute::CAMPAIGN . '/comments',
            [
                [
                    'methods' => WP_REST_Server::READABLE,
                    'callback' => [$this, 'get_items'],
                    'permission_callback' => '__return_true', // Public endpoint; access is validated inside get_items() based on campaign status and page privacy.
                    'args' => [
                        'id' => [
                            'type' => 'integer',
                            'required' => true,
                            'sanitize_callback' => 'absint',
                        ],
                        'perPage' => [
                            'type' => 'integer',
                            'required' => false,
                            'sanitize_callback' => 'absint',
                        ],
                        'anonymous' => [
                            'type' => 'boolean',
                            'required' => false,
                            'default'  => true,
                        ],
                    ],
                ],
                'schema' => [$this, 'get_public_item_schema'],
            ]
        );
    }

    /**
     * @since 4.14.6 check campaign status to block comments on inactive campaigns for non-admins
     * @since 4.0.0
     *
     * @throws Exception
     *
     * @return WP_REST_Response|WP_Error
     */
    public function get_items($request)
    {
        $campaignId = $request->get_param('id');
        $perPage = $request->get_param('perPage');
        $anonymous = $request->get_param('anonymous');

        $campaign = Campaign::find($campaignId);

        if (!$campaign) {
            $response = new WP_Error('campaign_not_found', __('Campaign not found', 'give'), ['status' => 404]);

            return rest_ensure_response($response);
        }

        $canViewPrivate = UserPermissions::campaigns()->canViewPrivate();

        if (!$campaign->status->isActive() && !$canViewPrivate) {
            return rest_ensure_response(
                new WP_Error(
                    'rest_forbidden',
                    __('You do not have permission to view this campaign.', 'give'),
                    ['status' => CampaignPermissions::authorizationStatusCode()]
                )
            );
        }

        $query = (new CampaignDonationQuery($campaign))
            ->joinDonationMeta(DonationMetaKeys::DONOR_ID, 'donorIdMeta')
            ->joinDonationMeta(DonationMetaKeys::COMMENT, 'commentMeta')
            ->joinDonationMeta(DonationMetaKeys::ANONYMOUS, 'anonymousMeta')
            ->leftJoin('give_donors', 'donorIdMeta.meta_value', 'donors.id', 'donors');

        if (!$anonymous) {
            $query->where('anonymousMeta.meta_value', '1', '!=');
        }

        $query->where('commentMeta.meta_value', '', '!=');
        $query->whereIsNotNull('commentMeta.meta_value');

        $query->select(
            'donorIdMeta.meta_value as donorId',
            'commentMeta.meta_value as comment',
            'anonymousMeta.meta_value as anonymous',
            'donation.post_date as date',
            'donors.name as donorName',
            'donors.email as email'
        );

        $donations = $query->limit($perPage)->getAll();

        $formattedComments = array_map(function ($donation) {
            $donorName = $donation->anonymous === '1' ? __('Anonymous') : $donation->donorName;
            $avatarEmail = $donation->anonymous === '1' ? '' : ($donation->email ?? '');

            return [
                'donorName' => $donorName,
                'comment' => $donation->comment,
                'anonymous' => $donation->anonymous === '1',
                'date' => human_time_diff(strtotime($donation->date)),
                'avatar' => (string) get_avatar_url($avatarEmail),
            ];
        }, $donations);

        $items = new WP_REST_Response($formattedComments);

        return rest_ensure_response($items);
    }

    /**
     * @since 4.13.0
     */
    public function get_item_schema(): array
    {
        return [
            '$schema' => 'http://json-schema.org/draft-04/schema#',
            'title' => 'givewp/campaign-comments',
            'description' => esc_html__('Provides comments for a specific campaign.', 'give'),
            'type' => 'object',
            'properties' => [
                'id' => [
                    'type' => 'integer',
                    'description' => esc_html__('The Campaign ID.', 'give'),
                    'required' => true,
                ],
                'perPage' => [
                    'type' => 'integer',
                    'description' => esc_html__('Comments per page', 'give'),
                ],
                'anonymous' => [
                    'type' => 'boolean',
                    'description' => esc_html__('Include anonymous comments', 'give'),
                ],
            ],
        ];
    }
}
