<?php
/**
 * 1MZ For Artists — Store Change Requests Endpoints
 *
 * Adiciona endpoints para o artista:
 *   - Ver elegibilidade + catálogo de lojas + custo estimado
 *   - Ver pedido pendente (se houver)
 *   - Criar pedido de alteração de lojas
 *   - Cancelar o seu próprio pedido pendente
 *
 *   GET    /releases/{id}/store-changes/eligibility
 *   GET    /releases/{id}/store-changes/pending
 *   POST   /releases/{id}/store-changes
 *   DELETE /releases/{id}/store-changes/{request_id}
 *
 * Reutiliza 100% da lógica existente em distribution-store-requests.php:
 *   - rmbz_store_get_catalog($only_active=true)
 *   - rmbz_store_count_approved_changes($release_id, $user_tel)
 *   - rmbz_store_calculate_fee($release_id, $user_tel, $added_dsps)
 *   - rmbz_store_create_request($release_id, $user_tel, $proposed_dsps)
 *
 * @package 1MZ_For_Artists
 * @since 1.6.19
 */

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

if ( ! defined( 'RMBZ_API_STORE_CHANGES_VERSION' ) ) {
    define( 'RMBZ_API_STORE_CHANGES_VERSION', '1.6.19.1' );
}

add_action( 'rest_api_init', 'rmbz_api_register_store_changes_routes' );

function rmbz_api_register_store_changes_routes() {
    register_rest_route( RMBZ_API_NAMESPACE,
        '/releases/(?P<id>\d+)/store-changes/eligibility', [
            'methods'             => 'GET',
            'callback'            => 'rmbz_api_handle_store_changes_eligibility',
            'permission_callback' => 'rmbz_api_require_auth',
            'args' => [
                'id' => [ 'type' => 'integer', 'required' => true ],
            ],
        ]
    );

    register_rest_route( RMBZ_API_NAMESPACE,
        '/releases/(?P<id>\d+)/store-changes/pending', [
            'methods'             => 'GET',
            'callback'            => 'rmbz_api_handle_store_changes_pending',
            'permission_callback' => 'rmbz_api_require_auth',
            'args' => [
                'id' => [ 'type' => 'integer', 'required' => true ],
            ],
        ]
    );

    register_rest_route( RMBZ_API_NAMESPACE,
        '/releases/(?P<id>\d+)/store-changes', [
            'methods'             => 'POST',
            'callback'            => 'rmbz_api_handle_store_changes_create',
            'permission_callback' => 'rmbz_api_require_auth',
            'args' => [
                'id'  => [ 'type' => 'integer', 'required' => true ],
                'dsps'=> [ 'required' => true ],
            ],
        ]
    );

    register_rest_route( RMBZ_API_NAMESPACE,
        '/releases/(?P<id>\d+)/store-changes/(?P<request_id>\d+)', [
            'methods'             => 'DELETE',
            'callback'            => 'rmbz_api_handle_store_changes_cancel',
            'permission_callback' => 'rmbz_api_require_auth',
            'args' => [
                'id'         => [ 'type' => 'integer', 'required' => true ],
                'request_id' => [ 'type' => 'integer', 'required' => true ],
            ],
        ]
    );
}


/* ============================================================================
 * HELPERS
 * ============================================================================ */

/**
 * Devolve a release se pertencer ao utilizador, senão null.
 */
function rmbz_api_store_get_owned_release( $id, $tel ) {
    global $wpdb;
    return $wpdb->get_row( $wpdb->prepare(
        "SELECT id, title, status, artist_telemovel
         FROM {$wpdb->prefix}rmbz_distro_releases
         WHERE id = %d AND artist_telemovel = %s",
        (int) $id, (string) $tel
    ) );
}

/**
 * Devolve as DSPs actuais de um release como array de slugs.
 */
function rmbz_api_store_get_current_dsps( $release_id ) {
    if ( ! function_exists( 'rmbz_distro_get_platforms' ) ) return [];
    $p = rmbz_distro_get_platforms( (int) $release_id );
    if ( ! $p ) return [];
    return (array) ( $p->_dsp_list ?? [] );
}

/**
 * Formata um pedido para a resposta API.
 */
function rmbz_api_store_format_request( $row ) {
    if ( ! $row ) return null;
    $decoded = function( $json ) {
        $d = json_decode( (string) $json, true );
        return is_array( $d ) ? array_values( $d ) : [];
    };
    return [
        'id'              => (int) $row->id,
        'release_id'      => (int) $row->release_id,
        'status'          => (string) $row->status,
        'current_dsps'    => $decoded( $row->current_dsps_snapshot ),
        'proposed_dsps'   => $decoded( $row->proposed_dsps ),
        'added_dsps'      => $decoded( $row->added_dsps ),
        'removed_dsps'    => $decoded( $row->removed_dsps ),
        'is_first_change' => (bool) $row->is_first_change,
        'fee_amount'      => (float) $row->fee_amount,
        'fee_charged'     => (bool) $row->fee_charged,
        'admin_note'      => $row->admin_note ?: null,
        'created_at'      => $row->created_at ? mysql_to_rfc3339( $row->created_at ) : null,
        'decided_at'      => isset($row->decided_at) && $row->decided_at
            ? mysql_to_rfc3339( $row->decided_at )
            : null,
    ];
}


/* ============================================================================
 * GET /releases/{id}/store-changes/eligibility
 *
 * Devolve:
 *   - eligible: bool (status do release permite, sistema activado, etc.)
 *   - reason: string com motivo se !eligible
 *   - catalog: lista das DSPs activas com { slug, name, tier, logo_url }
 *   - current_dsps: lista de slugs onde o release está
 *   - approved_changes_count: nº de pedidos já aprovados deste user
 *   - subsequent_fee: custo configurado (rmbz_store_change_fee_subsequent)
 *   - has_pending: bool (se já existe pedido pendente — bloqueia novos)
 * ============================================================================ */
function rmbz_api_handle_store_changes_eligibility( WP_REST_Request $request ) {
    $tel = (string) $request->get_param( 'rmbz_telemovel' );
    $id  = (int) $request->get_param( 'id' );

    $rel = rmbz_api_store_get_owned_release( $id, $tel );
    if ( ! $rel ) {
        return rmbz_api_error( 'Release não encontrado.', 404, 'not_found' );
    }

    // Sistema desactivado globalmente?
    $enabled = (bool) get_option( 'rmbz_store_changes_enabled', true );

    // Status válido?
    $allowed = [ 'live', 'distribuido', 'delivered' ];
    $status_ok = in_array( $rel->status, $allowed, true );

    // Existe pedido pendente?
    global $wpdb;
    $table = $wpdb->prefix . 'rmbz_store_change_requests';
    $has_pending = false;
    if ( $wpdb->get_var( "SHOW TABLES LIKE '$table'" ) === $table ) {
        $has_pending = (int) $wpdb->get_var( $wpdb->prepare(
            "SELECT COUNT(*) FROM $table WHERE release_id = %d AND status = 'pending'",
            $id
        ) ) > 0;
    }

    $eligible = $enabled && $status_ok && ! $has_pending;
    $reason = '';
    if ( ! $enabled )      $reason = 'system_disabled';
    elseif ( ! $status_ok) $reason = 'release_not_live';
    elseif ( $has_pending) $reason = 'pending_exists';

    // Catálogo
    $catalog_raw = function_exists( 'rmbz_store_get_catalog' )
        ? rmbz_store_get_catalog( true )
        : [];
    $catalog = [];
    foreach ( $catalog_raw as $slug => $info ) {
        $catalog[] = [
            'slug'     => (string) $slug,
            'name'     => (string) $info['name'],
            'tier'     => (int) ( $info['tier'] ?? 2 ),
            'logo_url' => (string) ( $info['logo_url'] ?? '' ),
        ];
    }

    $approved_count = function_exists( 'rmbz_store_count_approved_changes' )
        ? (int) rmbz_store_count_approved_changes( $id, $tel )
        : 0;

    $subsequent_fee = (float) get_option( 'rmbz_store_change_fee_subsequent', 100 );
    $current_dsps   = rmbz_api_store_get_current_dsps( $id );

    return rmbz_api_ok( [
        '_api_version'           => RMBZ_API_STORE_CHANGES_VERSION,
        'eligible'               => $eligible,
        'reason'                 => $reason,
        'catalog'                => $catalog,
        'current_dsps'           => array_values( $current_dsps ),
        'approved_changes_count' => $approved_count,
        'subsequent_fee'         => $subsequent_fee,
        'has_pending'            => $has_pending,
    ] );
}


/* ============================================================================
 * GET /releases/{id}/store-changes/pending
 *
 * Devolve o pedido pendente do utilizador para esta release, ou null
 * se não houver. Incluímos detalhes calculados (added/removed) para a
 * UI mostrar imediatamente sem ter de cruzar com o catálogo.
 * ============================================================================ */
function rmbz_api_handle_store_changes_pending( WP_REST_Request $request ) {
    $tel = (string) $request->get_param( 'rmbz_telemovel' );
    $id  = (int) $request->get_param( 'id' );

    $rel = rmbz_api_store_get_owned_release( $id, $tel );
    if ( ! $rel ) {
        return rmbz_api_error( 'Release não encontrado.', 404, 'not_found' );
    }

    global $wpdb;
    $table = $wpdb->prefix . 'rmbz_store_change_requests';
    if ( $wpdb->get_var( "SHOW TABLES LIKE '$table'" ) !== $table ) {
        return rmbz_api_ok( [
            '_api_version' => RMBZ_API_STORE_CHANGES_VERSION,
            'pending'      => null,
        ] );
    }

    $row = $wpdb->get_row( $wpdb->prepare(
        "SELECT * FROM $table
         WHERE release_id = %d AND requester_telemovel = %s AND status = 'pending'
         ORDER BY id DESC LIMIT 1",
        $id, $tel
    ) );

    return rmbz_api_ok( [
        '_api_version' => RMBZ_API_STORE_CHANGES_VERSION,
        'pending'      => rmbz_api_store_format_request( $row ),
    ] );
}


/* ============================================================================
 * POST /releases/{id}/store-changes
 *
 * Body: { "dsps": ["spotify", "apple_music", "deezer"] }
 *
 * Cria um pedido novo. O servidor:
 *   - Valida que release pertence ao user e está em estado live/distribuido
 *   - Valida slugs contra catálogo activo (descarta inválidos silenciosamente)
 *   - Calcula diff (added/removed) vs DSPs actuais
 *   - Calcula custo (1ª = 0, subsequente = só se houver adições)
 *   - Garante que não há outro pedido pendente
 *   - Cria registo (status = pending)
 * ============================================================================ */
function rmbz_api_handle_store_changes_create( WP_REST_Request $request ) {
    $tel = (string) $request->get_param( 'rmbz_telemovel' );
    $id  = (int) $request->get_param( 'id' );

    $rel = rmbz_api_store_get_owned_release( $id, $tel );
    if ( ! $rel ) {
        return rmbz_api_error( 'Release não encontrado.', 404, 'not_found' );
    }

    if ( ! (bool) get_option( 'rmbz_store_changes_enabled', true ) ) {
        return rmbz_api_error( 'Sistema de pedidos de alteração desactivado.', 409, 'system_disabled' );
    }

    $allowed = [ 'live', 'distribuido', 'delivered' ];
    if ( ! in_array( $rel->status, $allowed, true ) ) {
        return rmbz_api_error(
            'Só podes pedir alteração de lojas quando o release está nas lojas.',
            409,
            'release_not_live'
        );
    }

    $dsps = $request->get_param( 'dsps' );
    if ( ! is_array( $dsps ) ) {
        return rmbz_api_error( 'Campo "dsps" deve ser um array de slugs.', 422, 'invalid_payload' );
    }
    $dsps = array_map( 'sanitize_key', $dsps );

    if ( ! function_exists( 'rmbz_store_create_request' ) ) {
        return rmbz_api_error(
            'Sistema indisponível: módulo de pedidos não carregado.',
            500,
            'store_module_missing'
        );
    }

    $result = rmbz_store_create_request( (int) $id, $tel, $dsps );

    if ( is_wp_error( $result ) ) {
        $code = $result->get_error_code();
        $msg  = $result->get_error_message();
        // Mapear códigos para HTTP — 'pending_exists' e 'no_change' são 409
        $status = in_array( $code, [ 'pending_exists', 'no_change' ], true ) ? 409 : 400;
        return rmbz_api_error( $msg, $status, $code );
    }

    // Devolver o pedido criado (já formatado) para a UI mostrar imediatamente
    global $wpdb;
    $table = $wpdb->prefix . 'rmbz_store_change_requests';
    $row = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $table WHERE id = %d", (int) $result ) );

    return rmbz_api_ok( [
        '_api_version' => RMBZ_API_STORE_CHANGES_VERSION,
        'request'      => rmbz_api_store_format_request( $row ),
    ], 201 );
}


/* ============================================================================
 * DELETE /releases/{id}/store-changes/{request_id}
 *
 * Cancela um pedido PENDENTE do próprio utilizador.
 * Rejeita 404 se o pedido não existe ou pertence a outro user.
 * Rejeita 409 se o pedido já não está pending.
 * ============================================================================ */
function rmbz_api_handle_store_changes_cancel( WP_REST_Request $request ) {
    $tel        = (string) $request->get_param( 'rmbz_telemovel' );
    $release_id = (int) $request->get_param( 'id' );
    $request_id = (int) $request->get_param( 'request_id' );

    global $wpdb;
    $table = $wpdb->prefix . 'rmbz_store_change_requests';

    if ( $wpdb->get_var( "SHOW TABLES LIKE '$table'" ) !== $table ) {
        return rmbz_api_error( 'Pedido não encontrado.', 404, 'not_found' );
    }

    $row = $wpdb->get_row( $wpdb->prepare(
        "SELECT * FROM $table
         WHERE id = %d AND release_id = %d AND requester_telemovel = %s",
        $request_id, $release_id, $tel
    ) );

    if ( ! $row ) {
        return rmbz_api_error( 'Pedido não encontrado.', 404, 'not_found' );
    }
    if ( $row->status !== 'pending' ) {
        return rmbz_api_error(
            'Este pedido já foi processado e não pode ser cancelado.',
            409,
            'not_pending'
        );
    }

    $wpdb->update(
        $table,
        [
            'status'      => 'cancelled',
            'decided_at'  => current_time( 'mysql' ),
            'admin_note'  => 'Cancelado pelo artista via app.',
        ],
        [ 'id' => (int) $request_id ],
        [ '%s', '%s', '%s' ],
        [ '%d' ]
    );

    return rmbz_api_ok( [
        '_api_version' => RMBZ_API_STORE_CHANGES_VERSION,
        'cancelled'    => true,
        'request_id'   => (int) $request_id,
    ] );
}
