<?php
/**
 * 1MZ For Artists — Splits Endpoints
 *
 * Expõe o sistema de splits (colaboradores que recebem parte dos
 * royalties) via REST. Reutiliza 100% da lógica existente em:
 *
 *   - distribution-splits-frontend.php (handler frontend save)
 *   - distribution-splits-phases.php (fases + pedidos de alteração)
 *   - distribution-splits.php (auto-classify + notificações)
 *   - distribution-track-editor.php (rmbz_track_get_splits)
 *
 * ENDPOINTS:
 *   GET  /releases/{id}/splits                       — todas as tracks + splits + fase
 *   GET  /tracks/{trackId}/splits                    — splits de 1 faixa
 *   GET  /splits/roles                               — vocabulário de roles
 *   PUT  /tracks/{trackId}/splits                    — gravar splits (fases 1 e 2)
 *   POST /tracks/{trackId}/splits/request-change     — pedido alteração (fase 3)
 *   GET  /releases/{id}/splits/pending-requests      — pedidos pendentes do user
 *
 * REGRAS DE NEGÓCIO (já implementadas pelo plugin):
 *   - Fase 1 (incomplete/draft): edição directa, rate-limit 3/30 dias
 *   - Fase 2 (live mas sem royalties): edição directa
 *   - Fase 3 (já tem holdings): só via pedido de alteração ao admin
 *   - Soma das percentagens NÃO pode passar 100% (resto fica para o owner)
 *   - Não pode criar split para si próprio
 *   - Auto-accept se telemóvel está registado, senão external_hold
 *
 * @package 1MZ_For_Artists
 * @since 1.6.20
 */

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

if ( ! defined( 'RMBZ_API_SPLITS_VERSION' ) ) {
    define( 'RMBZ_API_SPLITS_VERSION', '1.6.20.1' );
}

add_action( 'rest_api_init', 'rmbz_api_register_splits_routes' );

function rmbz_api_register_splits_routes() {
    register_rest_route( RMBZ_API_NAMESPACE, '/releases/(?P<id>\d+)/splits', [
        'methods'             => 'GET',
        'callback'            => 'rmbz_api_handle_get_release_splits',
        'permission_callback' => 'rmbz_api_require_auth',
        'args' => [ 'id' => [ 'type' => 'integer', 'required' => true ] ],
    ] );

    register_rest_route( RMBZ_API_NAMESPACE, '/tracks/(?P<track_id>\d+)/splits', [
        [
            'methods'             => 'GET',
            'callback'            => 'rmbz_api_handle_get_track_splits',
            'permission_callback' => 'rmbz_api_require_auth',
            'args' => [ 'track_id' => [ 'type' => 'integer', 'required' => true ] ],
        ],
        [
            'methods'             => 'PUT',
            'callback'            => 'rmbz_api_handle_save_track_splits',
            'permission_callback' => 'rmbz_api_require_auth',
            'args' => [
                'track_id' => [ 'type' => 'integer', 'required' => true ],
                'splits'   => [ 'required' => true ],
            ],
        ],
    ] );

    register_rest_route( RMBZ_API_NAMESPACE, '/splits/roles', [
        'methods'             => 'GET',
        'callback'            => 'rmbz_api_handle_splits_roles',
        'permission_callback' => 'rmbz_api_require_auth',
    ] );

    register_rest_route( RMBZ_API_NAMESPACE, '/tracks/(?P<track_id>\d+)/splits/request-change', [
        'methods'             => 'POST',
        'callback'            => 'rmbz_api_handle_request_split_change',
        'permission_callback' => 'rmbz_api_require_auth',
        'args' => [
            'track_id' => [ 'type' => 'integer', 'required' => true ],
            'splits'   => [ 'required' => true ],
        ],
    ] );

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


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

/**
 * Devolve a release se pertencer ao utilizador, senão null.
 */
function rmbz_api_splits_get_owned_release( $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) $release_id, (string) $tel
    ) );
}

/**
 * Devolve a track se pertencer a uma release do utilizador, ou null.
 * Devolve também o release_id (para validações posteriores).
 */
function rmbz_api_splits_get_owned_track( $track_id, $tel ) {
    global $wpdb;
    return $wpdb->get_row( $wpdb->prepare(
        "SELECT t.id, t.release_id, t.track_title, t.track_order, r.artist_telemovel, r.status
         FROM {$wpdb->prefix}rmbz_distro_tracks t
         JOIN {$wpdb->prefix}rmbz_distro_releases r ON r.id = t.release_id
         WHERE t.id = %d AND r.artist_telemovel = %s",
        (int) $track_id, (string) $tel
    ) );
}

/**
 * Formata uma linha de split para a resposta API.
 */
function rmbz_api_splits_format_row( $row ) {
    if ( ! $row ) return null;
    return [
        'id'                     => (int) $row->id,
        'track_id'               => (int) $row->track_id,
        'release_id'             => isset($row->release_id) ? (int) $row->release_id : null,
        'collaborator_name'      => (string) $row->collaborator_name,
        'collaborator_telemovel' => (string) $row->collaborator_telemovel,
        'role'                   => (string) $row->role,
        'percentage'             => (float) $row->percentage,
        'invite_status'          => (string) $row->invite_status,
        'created_at'             => isset($row->created_at) && $row->created_at
            ? mysql_to_rfc3339( $row->created_at ) : null,
    ];
}

/**
 * Calcula stats da soma + saldo para o owner.
 */
function rmbz_api_splits_compute_summary( $splits ) {
    $sum = 0.0;
    foreach ( $splits as $s ) {
        $sum += (float) $s['percentage'];
    }
    $sum = round( $sum, 2 );
    return [
        'total_collaborators_pct' => $sum,
        'owner_pct'               => round( max( 0, 100 - $sum ), 2 ),
        'is_valid'                => $sum >= 0 && $sum <= 100.01,
    ];
}

/**
 * Devolve info de rate-limit fase 1 sem registar.
 */
function rmbz_api_splits_phase1_status( $release_id ) {
    if ( ! function_exists( 'rmbz_splits_phase1_rate_check' ) ) {
        return [ 'limit' => 3, 'count' => 0, 'remaining' => 3, 'window_days' => 30 ];
    }
    $r = rmbz_splits_phase1_rate_check( $release_id, false );
    return [
        'limit'       => (int) ( $r['limit']  ?? 3 ),
        'count'       => (int) ( $r['count']  ?? 0 ),
        'remaining'   => max( 0, (int) ( $r['limit'] ?? 3 ) - (int) ( $r['count'] ?? 0 ) ),
        'window_days' => 30,
    ];
}


/* ============================================================================
 * GET /splits/roles  — vocabulário
 * ============================================================================ */
function rmbz_api_handle_splits_roles( WP_REST_Request $request ) {
    $roles = function_exists( 'rmbz_track_collaborator_roles' )
        ? rmbz_track_collaborator_roles()
        : [];

    $items = [];
    foreach ( $roles as $slug => $label ) {
        $items[] = [ 'slug' => (string) $slug, 'label' => (string) $label ];
    }
    return rmbz_api_ok( [
        '_api_version' => RMBZ_API_SPLITS_VERSION,
        'roles'        => $items,
    ] );
}


/* ============================================================================
 * GET /releases/{id}/splits  — todas as tracks + splits + fase
 * ============================================================================ */
function rmbz_api_handle_get_release_splits( WP_REST_Request $request ) {
    $tel = (string) $request->get_param( 'rmbz_telemovel' );
    $id  = (int) $request->get_param( 'id' );

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

    $phase = function_exists( 'rmbz_splits_get_release_phase' )
        ? rmbz_splits_get_release_phase( $id )
        : 'unknown';
    $can_edit_directly = function_exists( 'rmbz_splits_can_edit_directly' )
        ? (bool) rmbz_splits_can_edit_directly( $id )
        : false;

    // Buscar tracks da release
    global $wpdb;
    $rows = $wpdb->get_results( $wpdb->prepare(
        "SELECT id, track_title, track_order, isrc_code, feat_artists, is_explicit
         FROM {$wpdb->prefix}rmbz_distro_tracks
         WHERE release_id = %d
         ORDER BY track_order ASC, id ASC",
        $id
    ) );

    $tracks = [];
    foreach ( (array) $rows as $t ) {
        $splits_raw = function_exists( 'rmbz_track_get_splits' )
            ? rmbz_track_get_splits( (int) $t->id )
            : [];
        $splits = [];
        foreach ( $splits_raw as $s ) {
            $splits[] = rmbz_api_splits_format_row( $s );
        }
        $summary = rmbz_api_splits_compute_summary( $splits );

        $tracks[] = [
            'id'           => (int) $t->id,
            'title'        => (string) $t->track_title,
            'order'        => (int) $t->track_order,
            'isrc'         => $t->isrc_code ?: null,
            'feat_artists' => $t->feat_artists ?: null,
            'is_explicit'  => (bool) $t->is_explicit,
            'splits'       => $splits,
            'summary'      => $summary,
        ];
    }

    return rmbz_api_ok( [
        '_api_version'      => RMBZ_API_SPLITS_VERSION,
        'release_id'        => (int) $rel->id,
        'release_title'     => (string) $rel->title,
        'release_status'    => (string) $rel->status,
        'phase'             => $phase,
        'can_edit_directly' => $can_edit_directly,
        'rate_limit'        => $phase === 'phase1' ? rmbz_api_splits_phase1_status( $id ) : null,
        'tracks'            => $tracks,
    ] );
}


/* ============================================================================
 * GET /tracks/{trackId}/splits  — splits de uma faixa
 * ============================================================================ */
function rmbz_api_handle_get_track_splits( WP_REST_Request $request ) {
    $tel      = (string) $request->get_param( 'rmbz_telemovel' );
    $track_id = (int) $request->get_param( 'track_id' );

    $track = rmbz_api_splits_get_owned_track( $track_id, $tel );
    if ( ! $track ) {
        return rmbz_api_error( 'Faixa não encontrada.', 404, 'not_found' );
    }

    $splits_raw = function_exists( 'rmbz_track_get_splits' )
        ? rmbz_track_get_splits( $track_id )
        : [];
    $splits = [];
    foreach ( $splits_raw as $s ) {
        $splits[] = rmbz_api_splits_format_row( $s );
    }

    $phase = function_exists( 'rmbz_splits_get_release_phase' )
        ? rmbz_splits_get_release_phase( (int) $track->release_id )
        : 'unknown';
    $can_edit_directly = function_exists( 'rmbz_splits_can_edit_directly' )
        ? (bool) rmbz_splits_can_edit_directly( (int) $track->release_id )
        : false;

    return rmbz_api_ok( [
        '_api_version'      => RMBZ_API_SPLITS_VERSION,
        'track_id'          => (int) $track->id,
        'track_title'       => (string) $track->track_title,
        'release_id'        => (int) $track->release_id,
        'phase'             => $phase,
        'can_edit_directly' => $can_edit_directly,
        'splits'            => $splits,
        'summary'           => rmbz_api_splits_compute_summary( $splits ),
    ] );
}


/* ============================================================================
 * PUT /tracks/{trackId}/splits  — gravar splits (fases 1 e 2)
 *
 * Body: {
 *   "splits": [
 *     { "name": "...", "telemovel": "...", "role": "feature", "percentage": 25.0 },
 *     ...
 *   ]
 * }
 *
 * Replica o handler AJAX rmbz_ajax_splits_frontend_save com mesmas regras:
 *   - Só fases 1 e 2 (em fase 3 devolve 409 com code='phase3_locked')
 *   - Rate limit fase 1: 3/30dias (devolve 429 se excedido)
 *   - Soma <= 100% (resto fica para owner)
 *   - Não permite split para o próprio user
 *   - Após gravar, dispara hook rmbz_track_splits_saved (auto-classify)
 * ============================================================================ */
function rmbz_api_handle_save_track_splits( WP_REST_Request $request ) {
    $tel      = (string) $request->get_param( 'rmbz_telemovel' );
    $track_id = (int) $request->get_param( 'track_id' );

    $track = rmbz_api_splits_get_owned_track( $track_id, $tel );
    if ( ! $track ) {
        return rmbz_api_error( 'Faixa não encontrada.', 404, 'not_found' );
    }

    $release_id = (int) $track->release_id;

    // Bloqueio por fase
    if ( function_exists( 'rmbz_splits_can_edit_directly' )
         && ! rmbz_splits_can_edit_directly( $release_id ) ) {
        return rmbz_api_error(
            'Esta release já gerou royalties. Edição directa de splits está '
            . 'bloqueada — usa o pedido de alteração para o admin avaliar.',
            409,
            'phase3_locked'
        );
    }

    // Rate limit fase 1
    if ( function_exists( 'rmbz_splits_get_release_phase' )
         && rmbz_splits_get_release_phase( $release_id ) === 'phase1' ) {
        $rate = rmbz_splits_phase1_rate_check( $release_id );
        if ( ! $rate['ok'] ) {
            return rmbz_api_error(
                $rate['message'] ?? 'Limite de alterações atingido. Tenta novamente daqui a uns dias.',
                429,
                'rate_limited'
            );
        }
    }

    $splits_input = $request->get_param( 'splits' );
    if ( ! is_array( $splits_input ) ) {
        return rmbz_api_error( 'Campo "splits" deve ser um array.', 422, 'invalid_payload' );
    }

    // Sanitizar e validar (mesma lógica do handler AJAX original)
    $clean = [];
    $sum   = 0.0;
    foreach ( $splits_input as $s ) {
        $name = trim( sanitize_text_field( (string) ( $s['name'] ?? '' ) ) );
        $stel = trim( sanitize_text_field( (string) ( $s['telemovel'] ?? '' ) ) );
        $role = sanitize_key( (string) ( $s['role'] ?? 'feature' ) );
        $pct  = (float) ( $s['percentage'] ?? 0 );

        if ( empty( $name ) || $pct <= 0 ) continue;
        if ( $pct > 100 ) {
            return rmbz_api_error(
                'Percentagem inválida em "' . $name . '" (' . $pct . '%).',
                422,
                'invalid_percentage'
            );
        }
        if ( empty( $stel ) ) {
            return rmbz_api_error(
                'Telemóvel obrigatório para "' . $name . '".',
                422,
                'missing_telemovel'
            );
        }
        if ( function_exists( 'rmbz_splits_normalize_telemovel' ) ) {
            $norm = rmbz_splits_normalize_telemovel( $stel );
            if ( ! empty( $norm ) ) $stel = $norm;
        }
        if ( $stel === $tel ) {
            return rmbz_api_error(
                'Não precisas de criar split para ti próprio. O que sobrar dos 100% fica automaticamente teu.',
                422,
                'self_split_not_allowed'
            );
        }
        $clean[] = [
            'name'       => $name,
            'telemovel'  => $stel,
            'role'       => $role,
            'percentage' => round( $pct, 2 ),
        ];
        $sum += $pct;
    }

    if ( $sum > 100.01 ) {
        return rmbz_api_error(
            'Soma das percentagens é ' . number_format( $sum, 2 ) . '% — não pode ultrapassar 100%.',
            422,
            'sum_over_100'
        );
    }

    global $wpdb;
    $t_splits = $wpdb->prefix . 'rmbz_track_splits';
    if ( $wpdb->get_var( "SHOW TABLES LIKE '$t_splits'" ) !== $t_splits ) {
        return rmbz_api_error( 'Tabela de splits não existe.', 500, 'no_table' );
    }

    // Replace (delete + insert) — igual ao handler AJAX
    $wpdb->delete( $t_splits, [ 'track_id' => $track_id ], [ '%d' ] );
    foreach ( $clean as $sp ) {
        $wpdb->insert( $t_splits, [
            'track_id'               => $track_id,
            'release_id'             => $release_id,
            'collaborator_name'      => $sp['name'],
            'collaborator_telemovel' => $sp['telemovel'],
            'role'                   => $sp['role'],
            'percentage'             => $sp['percentage'],
            'invite_status'          => 'pending',
        ], [ '%d', '%d', '%s', '%s', '%s', '%f', '%s' ] );
    }

    // Dispara o hook que classifica automaticamente (auto-accept ou external_hold)
    // e envia notificações aos colaboradores internos.
    do_action( 'rmbz_track_splits_saved', $track_id );

    // Audit log para rate-limit
    if ( function_exists( 'rmbz_splits_audit' ) ) {
        $phase = function_exists( 'rmbz_splits_get_release_phase' )
            ? rmbz_splits_get_release_phase( $release_id ) : 'unknown';
        rmbz_splits_audit(
            'frontend_save_' . $phase,
            $track_id,
            $release_id,
            null,
            null,
            wp_json_encode( $clean ),
            'Edição directa via app'
        );
    }

    // Devolver o estado novo (após auto-classify) para a UI mostrar invite_status correcto
    $splits_after = rmbz_track_get_splits( $track_id );
    $splits_out = [];
    foreach ( $splits_after as $s ) {
        $splits_out[] = rmbz_api_splits_format_row( $s );
    }

    return rmbz_api_ok( [
        '_api_version' => RMBZ_API_SPLITS_VERSION,
        'splits'       => $splits_out,
        'summary'      => rmbz_api_splits_compute_summary( $splits_out ),
        'message'      => 'Splits guardados.',
    ] );
}


/* ============================================================================
 * POST /tracks/{trackId}/splits/request-change  — pedido alteração (fase 3)
 *
 * Body: {
 *   "splits": [...],   // mesma estrutura do save
 *   "reason": "..."    // opcional, máx 500 chars
 * }
 *
 * Cria um pedido em rmbz_split_change_requests com status='pending'.
 * O admin avalia depois no painel WP existente.
 * ============================================================================ */
function rmbz_api_handle_request_split_change( WP_REST_Request $request ) {
    $tel      = (string) $request->get_param( 'rmbz_telemovel' );
    $track_id = (int) $request->get_param( 'track_id' );

    $track = rmbz_api_splits_get_owned_track( $track_id, $tel );
    if ( ! $track ) {
        return rmbz_api_error( 'Faixa não encontrada.', 404, 'not_found' );
    }
    $release_id = (int) $track->release_id;

    $phase = function_exists( 'rmbz_splits_get_release_phase' )
        ? rmbz_splits_get_release_phase( $release_id )
        : 'unknown';

    $splits_input = $request->get_param( 'splits' );
    if ( ! is_array( $splits_input ) ) {
        return rmbz_api_error( 'Campo "splits" deve ser um array.', 422, 'invalid_payload' );
    }

    $reason = trim( sanitize_textarea_field( (string) ( $request->get_param( 'reason' ) ?? '' ) ) );
    if ( mb_strlen( $reason ) > 500 ) {
        return rmbz_api_error( 'Motivo demasiado longo (máx 500 chars).', 422, 'reason_too_long' );
    }

    // Validar payload (mesma lógica do save)
    $clean = [];
    $sum   = 0.0;
    foreach ( $splits_input as $s ) {
        $name = trim( sanitize_text_field( (string) ( $s['name'] ?? '' ) ) );
        $stel = trim( sanitize_text_field( (string) ( $s['telemovel'] ?? '' ) ) );
        $role = sanitize_key( (string) ( $s['role'] ?? 'feature' ) );
        $pct  = (float) ( $s['percentage'] ?? 0 );

        if ( empty( $name ) ) continue;
        if ( $pct <= 0 ) continue;
        if ( $pct > 100 ) {
            return rmbz_api_error( 'Percentagem inválida em "' . $name . '".', 422, 'invalid_percentage' );
        }
        if ( empty( $stel ) ) {
            return rmbz_api_error( 'Telemóvel obrigatório para "' . $name . '".', 422, 'missing_telemovel' );
        }
        if ( function_exists( 'rmbz_splits_normalize_telemovel' ) ) {
            $norm = rmbz_splits_normalize_telemovel( $stel );
            if ( ! empty( $norm ) ) $stel = $norm;
        }
        $clean[] = [
            'name'       => $name,
            'telemovel'  => $stel,
            'role'       => $role,
            'percentage' => round( $pct, 2 ),
        ];
        $sum += $pct;
    }

    if ( $sum > 100.01 ) {
        return rmbz_api_error(
            'Soma das percentagens propostas excede 100%.',
            422,
            'sum_over_100'
        );
    }

    global $wpdb;

    // Já existe pedido pendente para esta track?
    $existing = (int) $wpdb->get_var( $wpdb->prepare(
        "SELECT COUNT(*) FROM {$wpdb->prefix}rmbz_split_change_requests
         WHERE track_id = %d AND status = 'pending'",
        $track_id
    ) );
    if ( $existing > 0 ) {
        return rmbz_api_error(
            'Já existe um pedido pendente para esta faixa. Aguarda decisão do admin.',
            409,
            'pending_exists'
        );
    }

    // Snapshot dos splits actuais (para o admin comparar)
    $current = function_exists( 'rmbz_track_get_splits' )
        ? rmbz_track_get_splits( $track_id )
        : [];

    $ok = $wpdb->insert(
        $wpdb->prefix . 'rmbz_split_change_requests',
        [
            'release_id'              => $release_id,
            'track_id'                => $track_id,
            'requester_telemovel'     => $tel,
            'reason'                  => $reason,
            'proposed_splits'         => wp_json_encode( $clean ),
            'current_splits_snapshot' => wp_json_encode( $current ),
            'phase_at_request'        => $phase,
            'status'                  => 'pending',
        ],
        [ '%d', '%d', '%s', '%s', '%s', '%s', '%s', '%s' ]
    );

    if ( ! $ok ) {
        return rmbz_api_error( 'Erro ao registar o pedido.', 500, 'db_error' );
    }
    $request_id = (int) $wpdb->insert_id;

    // Notificar admin (reusa função existente)
    if ( function_exists( 'rmbz_splits_phases_notify_admin_new_request' ) ) {
        rmbz_splits_phases_notify_admin_new_request( $request_id );
    }

    return rmbz_api_ok( [
        '_api_version' => RMBZ_API_SPLITS_VERSION,
        'request_id'   => $request_id,
        'message'      => 'Pedido enviado. O admin vai avaliar e contactar-te.',
    ], 201 );
}


/* ============================================================================
 * GET /releases/{id}/splits/pending-requests
 *
 * Lista os pedidos de alteração de splits ainda pendentes que o user fez
 * para esta release. Usado para mostrar badges/avisos na UI.
 * ============================================================================ */
function rmbz_api_handle_get_pending_split_requests( WP_REST_Request $request ) {
    $tel = (string) $request->get_param( 'rmbz_telemovel' );
    $id  = (int) $request->get_param( 'id' );

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

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

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

    $items = [];
    foreach ( (array) $rows as $r ) {
        $proposed = json_decode( $r->proposed_splits, true );
        $items[] = [
            'id'             => (int) $r->id,
            'track_id'       => (int) $r->track_id,
            'reason'         => $r->reason ?: null,
            'proposed_count' => is_array( $proposed ) ? count( $proposed ) : 0,
            'created_at'     => $r->created_at ? mysql_to_rfc3339( $r->created_at ) : null,
        ];
    }

    return rmbz_api_ok( [
        '_api_version' => RMBZ_API_SPLITS_VERSION,
        'requests'     => $items,
    ] );
}
