<?php
/**
 * 1MZ Music Player — Subscrições VIP
 *
 * Fluxo: o app cria um PEDIDO (POST /account/subscribe). O pedido fica
 * pendente até o pagamento ser confirmado. Ao aprovar (admin, ou um gateway
 * no futuro) o VIP é concedido automaticamente pelo período do plano.
 *
 * @package 1MZ_Music_Player
 */

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

add_action( 'rest_api_init', 'mp_register_subscription_routes' );

function mp_register_subscription_routes() {
    register_rest_route( MP_API_NAMESPACE, '/account/subscribe', [
        'methods'             => 'POST',
        'callback'            => 'mp_handle_subscribe',
        'permission_callback' => '__return_true',
    ] );
    register_rest_route( MP_API_NAMESPACE, '/account/subscription', [
        'methods'             => 'GET',
        'callback'            => 'mp_handle_subscription_status',
        'permission_callback' => '__return_true',
    ] );
    register_rest_route( MP_API_NAMESPACE, '/account/subscription/cancel', [
        'methods'             => 'POST',
        'callback'            => 'mp_handle_subscription_cancel',
        'permission_callback' => '__return_true',
    ] );
}

/** Dias de validade por plano. */
function mp_plan_period_days( $plan ) {
    return $plan === 'annual' ? 365 : 30;
}

/** Cria um pedido VIP pendente para a conta autenticada. */
function mp_handle_subscribe( WP_REST_Request $request ) {
    global $wpdb;
    $row = mp_account_from_request( $request );
    if ( ! $row ) {
        return rmbz_api_error( 'Inicia sessão para assinar.', 401, 'unauthorized' );
    }
    if ( mp_is_vip( $row ) && empty( $row->vip_until ) ) {
        return rmbz_api_error( 'A tua conta já possui VIP vitalício.', 409, 'lifetime_vip' );
    }

    $plan = sanitize_text_field( (string) $request->get_param( 'plan' ) );
    if ( ! in_array( $plan, [ 'monthly', 'annual' ], true ) ) {
        $plan = 'monthly';
    }
    $vip      = mp_vip_config();
    $amount   = $plan === 'annual' ? $vip['annual_price'] : $vip['monthly_price'];
    $period   = mp_plan_period_days( $plan );
    $orders   = $wpdb->prefix . 'mp_vip_orders';

    // Reaproveita um pedido pendente do mesmo plano, se existir.
    $existing = $wpdb->get_row( $wpdb->prepare(
        "SELECT * FROM {$orders} WHERE account_id = %d AND status = 'pending' AND plan = %s ORDER BY id DESC LIMIT 1",
        $row->id, $plan
    ) );
    if ( $existing ) {
        return rmbz_api_ok( mp_order_payload( $existing, $vip ) );
    }

    $reference = 'MZ-' . strtoupper( substr( bin2hex( random_bytes( 6 ) ), 0, 8 ) );
    $wpdb->insert( $orders, [
        'account_id'  => $row->id,
        'plan'        => $plan,
        'amount'      => $amount,
        'currency'    => $vip['currency'],
        'period_days' => $period,
        'reference'   => $reference,
        'status'      => 'pending',
        'created_at'  => current_time( 'mysql', true ),
    ] );
    $id = (int) $wpdb->insert_id;
    if ( ! $id ) {
        return rmbz_api_error( 'Não foi possível criar o pedido.', 500, 'order_failed' );
    }
    $order = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$orders} WHERE id = %d", $id ) );
    do_action( 'mp_vip_order_created', $order );
    return rmbz_api_ok( mp_order_payload( $order, $vip ) );
}

/** Estado da subscrição da conta (VIP activo e/ou pedido pendente). */
function mp_handle_subscription_status( WP_REST_Request $request ) {
    global $wpdb;
    $row = mp_account_from_request( $request );
    if ( ! $row ) {
        return rmbz_api_error( 'Sessão inválida.', 401, 'unauthorized' );
    }
    $orders  = $wpdb->prefix . 'mp_vip_orders';
    $pending = $wpdb->get_row( $wpdb->prepare(
        "SELECT * FROM {$orders} WHERE account_id = %d AND status = 'pending' ORDER BY id DESC LIMIT 1",
        $row->id
    ) );
    $active_order = $wpdb->get_row( $wpdb->prepare(
        "SELECT * FROM {$orders} WHERE account_id = %d AND status = 'active' ORDER BY activated_at DESC, id DESC LIMIT 1",
        $row->id
    ) );
    $history_rows = $wpdb->get_results( $wpdb->prepare(
        "SELECT * FROM {$orders} WHERE account_id = %d ORDER BY id DESC LIMIT 12",
        $row->id
    ) );
    $is_vip = mp_is_vip( $row );
    $days_left = ( $is_vip && ! empty( $row->vip_until ) )
        ? max( 0, (int) ceil( ( strtotime( $row->vip_until ) - time() ) / DAY_IN_SECONDS ) )
        : null;
    $device_state = mp_account_devices_state( $row, mp_request_token_hash( $request ) );
    $vip_config = mp_vip_config();
    return rmbz_api_ok( [
        'is_vip'    => $is_vip,
        'vip_until' => $row->vip_until,
        'vip_source' => $is_vip ? mp_vip_source( $row ) : null,
        'days_left' => $days_left,
        'active_plan' => $active_order ? $active_order->plan : null,
        'renewal_recommended' => $days_left !== null && $days_left <= 7,
        'renewal_allowed' => ! ( $is_vip && empty( $row->vip_until ) ),
        'cloud_audio_allowed' => mp_account_cloud_audio_allowed( $row ),
        'pending'   => $pending ? mp_order_payload( $pending, $vip_config ) : null,
        'history'   => array_map( function ( $order ) use ( $vip_config ) {
            return mp_order_payload( $order, $vip_config );
        }, $history_rows ?: [] ),
        'devices'   => $device_state,
        'plans'     => [
            'currency' => $vip_config['currency'],
            'monthly' => $vip_config['monthly_price'],
            'annual' => $vip_config['annual_price'],
            'annual_per_month' => $vip_config['annual_per_month'],
            'savings_percent' => $vip_config['savings_percent'],
        ],
    ] );
}

function mp_handle_subscription_cancel( WP_REST_Request $request ) {
    global $wpdb;
    $row = mp_account_from_request( $request );
    if ( ! $row ) {
        return rmbz_api_error( 'Sessão inválida.', 401, 'unauthorized' );
    }
    $order_id = absint( $request->get_param( 'order_id' ) );
    $orders = $wpdb->prefix . 'mp_vip_orders';
    $updated = $wpdb->update(
        $orders,
        [ 'status' => 'cancelled' ],
        [ 'id' => $order_id, 'account_id' => (int) $row->id, 'status' => 'pending' ]
    );
    if ( ! $updated ) {
        return rmbz_api_error( 'Este pedido já não pode ser cancelado.', 409, 'order_not_pending' );
    }
    return rmbz_api_ok( [ 'cancelled' => true, 'order_id' => $order_id ] );
}

/** Payload de um pedido para o app (inclui instruções de pagamento). */
function mp_order_payload( $order, $vip ) {
    $instructions = (string) get_option( 'mp_vip_pay_instructions', '' );
    return [
        'order_id'     => (int) $order->id,
        'reference'    => $order->reference,
        'plan'         => $order->plan,
        'amount'       => $order->amount,
        'currency'     => $order->currency,
        'status'       => $order->status,
        'created_at'   => isset( $order->created_at ) ? (string) $order->created_at : '',
        'activated_at' => isset( $order->activated_at ) ? (string) $order->activated_at : '',
        'expires_at'   => isset( $order->expires_at ) ? (string) $order->expires_at : '',
        'instructions' => $instructions !== '' ? $instructions : 'Conclui o pagamento e o VIP será activado após confirmação.',
        'pay_url'      => $vip['cta_url'],
    ];
}

/** Concede VIP a uma conta pelo nº de dias (acumula se já tiver). */
function mp_grant_vip( $account_id, $period_days ) {
    global $wpdb;
    $table = $wpdb->prefix . 'mp_accounts';
    $acc = $wpdb->get_row( $wpdb->prepare(
        "SELECT is_vip, vip_until, vip_source, vip_full_until FROM {$table} WHERE id = %d",
        $account_id
    ) );
    $now = time();
    $active = $acc && mp_vip_is_active( $acc );
    $source = $acc ? mp_vip_source( $acc ) : 'paid';

    // Uma conta vitalícia concedida pelo admin/legado não deve ser rebaixada.
    if ( $active && empty( $acc->vip_until ) && in_array( $source, [ 'admin', 'legacy' ], true ) ) {
        return gmdate( 'Y-m-d H:i:s', $now + $period_days * DAY_IN_SECONDS );
    }

    $base = ( $active && ! empty( $acc->vip_until ) ) ? strtotime( $acc->vip_until ) : $now;
    $until = gmdate( 'Y-m-d H:i:s', $base + $period_days * DAY_IN_SECONDS );
    $full_base = ( $active && ! empty( $acc->vip_full_until ) && strtotime( $acc->vip_full_until ) > $now )
        ? strtotime( $acc->vip_full_until )
        : $now;
    if ( $active && in_array( $source, [ 'paid', 'legacy' ], true ) && empty( $acc->vip_full_until ) ) {
        $full_base = $base;
    }
    $full_until = gmdate( 'Y-m-d H:i:s', $full_base + $period_days * DAY_IN_SECONDS );
    $new_source = $active && in_array( $source, [ 'rewarded', 'mixed' ], true ) ? 'mixed' : 'paid';
    $updated = $wpdb->update( $table, [
        'is_vip'        => 1,
        'vip_until'     => $until,
        'vip_source'    => $new_source,
        'vip_full_until' => $full_until,
    ], [ 'id' => $account_id ] );
    return false === $updated ? false : $until;
}

/** Aprova um pedido (pagamento confirmado) → concede VIP. */
function mp_approve_order( $order_id ) {
    global $wpdb;
    $orders = $wpdb->prefix . 'mp_vip_orders';
    $wpdb->query( 'START TRANSACTION' );
    $claimed = $wpdb->query( $wpdb->prepare(
        "UPDATE {$orders} SET status = 'processing' WHERE id = %d AND status = 'pending'",
        $order_id
    ) );
    if ( 1 !== $claimed ) {
        $wpdb->query( 'ROLLBACK' );
        return false;
    }
    $order = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$orders} WHERE id = %d", $order_id ) );
    if ( ! $order ) {
        $wpdb->query( 'ROLLBACK' );
        return false;
    }
    $until = mp_grant_vip( $order->account_id, (int) $order->period_days );
    if ( ! $until ) {
        $wpdb->query( 'ROLLBACK' );
        return false;
    }
    $activated = $wpdb->update( $orders, [
        'status'       => 'active',
        'activated_at' => current_time( 'mysql', true ),
        'expires_at'   => $until,
    ], [ 'id' => $order_id, 'status' => 'processing' ] );
    if ( 1 !== $activated ) {
        $wpdb->query( 'ROLLBACK' );
        return false;
    }
    $wpdb->query( 'COMMIT' );
    do_action( 'mp_vip_order_approved', $order, $until );
    return true;
}

/** Rejeita / cancela um pedido pendente. */
function mp_reject_order( $order_id ) {
    global $wpdb;
    $orders = $wpdb->prefix . 'mp_vip_orders';
    return (bool) $wpdb->update( $orders, [ 'status' => 'rejected' ], [ 'id' => $order_id, 'status' => 'pending' ] );
}
