<?php
/**
 * 1MZ For Artists — Artist-side chat REST endpoints (live)
 *
 * Espelha /1mz/v1/admin-chat/* mas:
 *   - Auth via sessão de artista (rmbz_is_user_logged_in + telemovel)
 *   - Cada endpoint valida que o projeto pertence ao artista logado
 *   - Upload só se extra_data['artist_can_attach'] = true
 *   - Quando artista envia, espelha no artist_feedback legado para
 *     a UI antiga e a app móvel continuarem a ver via /projects
 *
 * Endpoints (base /wp-json/1mz/v1/artist-chat/{project_id}):
 *   GET  ?since=N        — listar (polling)
 *   POST /send           — enviar texto + anexo opcional (JSON)
 *   POST /upload         — multipart, valida toggle ON
 *   POST /delete         — apagar uma mensagem própria
 *   GET  /info           — devolve artist_can_attach + meta básica
 *
 * @package 1MZ_For_Artists
 * @since 1.5.197
 */

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

/* ============================================================================
 * Permission callback — aceita JWT (app) OU sessão (site)
 * ============================================================================
 *
 * A app móvel envia `Authorization: Bearer <jwt>` (validado por
 * rmbz_api_require_auth, que coloca o telemovel em rmbz_telemovel).
 *
 * O site /minha-conta/ usa sessão PHP (validada por rmbz_is_user_logged_in).
 *
 * Tentamos JWT primeiro porque é mais comum em apps; se falhar, tentamos
 * sessão como fallback. Se ambos falharem, devolve 401.
 *
 * Em qualquer caso, o telemovel autenticado fica em
 * $request->get_param('rmbz_telemovel') para os handlers usarem sem
 * revalidar.
 */
function rmbz_pchat_artist_perm( WP_REST_Request $req ) {
    // Tentativa 1: JWT (app)
    if ( function_exists( 'rmbz_api_require_auth' ) ) {
        $jwt_result = rmbz_api_require_auth( $req );
        if ( $jwt_result === true ) {
            return true; // telemovel já está em $req->get_param('rmbz_telemovel')
        }
        // Se falhou mas há header Authorization, NÃO tentar sessão
        // (significa que o app mandou um token inválido — não cair para
        // sessão silenciosamente).
        $auth_header = $req->get_header( 'authorization' );
        if ( ! empty( $auth_header ) ) {
            return $jwt_result; // o WP_Error da JWT
        }
    }

    // Tentativa 2: sessão (site)
    if ( function_exists( 'rmbz_is_user_logged_in' ) && rmbz_is_user_logged_in() ) {
        if ( function_exists( 'rmbz_get_current_user_telemovel' ) ) {
            $tel = rmbz_get_current_user_telemovel();
            if ( ! empty( $tel ) ) {
                $req->set_param( 'rmbz_telemovel', $tel );
                return true;
            }
        }
    }

    return new WP_Error( 'not_logged_in', 'Sessão expirada.', [ 'status' => 401 ] );
}

/**
 * Confirma que o projeto pertence ao artista autenticado.
 *
 * O telemovel vem do permission callback (que tentou JWT ou sessão e
 * meteu o valor em rmbz_telemovel). Retorna o telemovel ou WP_Error.
 */
function rmbz_pchat_artist_own_project( $project_id, $req = null ) {
    global $wpdb;
    $project_id = (int) $project_id;

    // Preferir o telemovel já validado pelo permission callback
    $tel = null;
    if ( $req instanceof WP_REST_Request ) {
        $tel = $req->get_param( 'rmbz_telemovel' );
    }
    // Fallback antigo (caso seja chamado de outro sítio sem $req)
    if ( empty( $tel ) && function_exists( 'rmbz_get_current_user_telemovel' ) ) {
        $tel = rmbz_get_current_user_telemovel();
    }
    if ( empty( $tel ) ) {
        return new WP_Error( 'no_tel', 'Não foi possível identificar o utilizador.', [ 'status' => 401 ] );
    }

    $owner = $wpdb->get_var( $wpdb->prepare(
        "SELECT artist_telemovel FROM {$wpdb->prefix}rmbz_artist_projects WHERE id = %d",
        $project_id
    ) );

    if ( $owner === null ) {
        return new WP_Error( 'not_found', 'Projeto não encontrado.', [ 'status' => 404 ] );
    }
    if ( (string) $owner !== (string) $tel ) {
        return new WP_Error( 'forbidden', 'Sem acesso a este projeto.', [ 'status' => 403 ] );
    }

    return $tel;
}

/* ============================================================================
 * Routes
 * ============================================================================ */
add_action( 'rest_api_init', function () {
    register_rest_route( '1mz/v1', '/artist-chat/(?P<id>\d+)', [
        'methods'             => 'GET',
        'callback'            => 'rmbz_pchat_artist_rest_get',
        'permission_callback' => 'rmbz_pchat_artist_perm',
        'args' => [
            'since' => [ 'type' => 'integer', 'default' => 0 ],
        ],
    ] );

    register_rest_route( '1mz/v1', '/artist-chat/(?P<id>\d+)/info', [
        'methods'             => 'GET',
        'callback'            => 'rmbz_pchat_artist_rest_info',
        'permission_callback' => 'rmbz_pchat_artist_perm',
    ] );

    register_rest_route( '1mz/v1', '/artist-chat/(?P<id>\d+)/send', [
        'methods'             => 'POST',
        'callback'            => 'rmbz_pchat_artist_rest_send',
        'permission_callback' => 'rmbz_pchat_artist_perm',
    ] );

    register_rest_route( '1mz/v1', '/artist-chat/(?P<id>\d+)/upload', [
        'methods'             => 'POST',
        'callback'            => 'rmbz_pchat_artist_rest_upload',
        'permission_callback' => 'rmbz_pchat_artist_perm',
    ] );

    register_rest_route( '1mz/v1', '/artist-chat/(?P<id>\d+)/delete', [
        'methods'             => 'POST',
        'callback'            => 'rmbz_pchat_artist_rest_delete',
        'permission_callback' => 'rmbz_pchat_artist_perm',
    ] );

    register_rest_route( '1mz/v1', '/artist-projects/filming-status', [
        'methods'             => 'GET',
        'callback'            => 'rmbz_pchat_artist_rest_filming_statuses',
        'permission_callback' => 'rmbz_pchat_artist_perm',
    ] );
} );

/* ============================================================================
 * Handlers
 * ============================================================================ */
function rmbz_pchat_artist_prepare_messages( $messages ) {
    $prepared = [];
    $now = time();
    $timezone = wp_timezone();

    foreach ( (array) $messages as $message ) {
        if ( ! empty( $message['is_deleted'] ) ) continue;

        $message['artist_can_delete'] = false;
        $message['artist_delete_until_ms'] = 0;
        $message_id = (int) ( $message['id'] ?? 0 );
        if ( $message_id > 0 && ( $message['author_type'] ?? '' ) === 'artist' && empty( $message['is_legacy'] ) ) {
            $created = DateTimeImmutable::createFromFormat( 'Y-m-d H:i:s', (string) ( $message['created_at'] ?? '' ), $timezone );
            if ( $created ) {
                $delete_until = $created->getTimestamp() + 120;
                $message['artist_delete_until_ms'] = $delete_until * 1000;
                $message['artist_can_delete'] = $now <= $delete_until;
            }
        }
        $prepared[] = $message;
    }
    return $prepared;
}

function rmbz_pchat_artist_rest_get( WP_REST_Request $req ) {
    $project_id = (int) $req['id'];
    $own = rmbz_pchat_artist_own_project( $project_id, $req );
    if ( is_wp_error( $own ) ) {
        return rmbz_api_error( $own->get_error_message(), (int) ( $own->get_error_data()['status'] ?? 400 ), $own->get_error_code() );
    }

    $since = (int) $req->get_param( 'since' );
    // O artista nunca vê marcadores de eliminação. A preparação também aplica
    // a janela de 2 minutos usando o relógio oficial do WordPress.
    $messages = rmbz_pchat_artist_prepare_messages( rmbz_pchat_get_messages( $project_id, $since ) );

    // marcar artist como leitor (mensagens novas)
    global $wpdb;
    if ( $since === 0 ) {
        $wpdb->update(
            $wpdb->prefix . 'rmbz_project_chat_messages',
            [ 'read_by_artist' => 1 ],
            [ 'project_id' => $project_id, 'read_by_artist' => 0 ],
            [ '%d' ], [ '%d', '%d' ]
        );
    }

    return rmbz_api_ok( [
        'messages'          => $messages,
        'deleted_message_ids' => rmbz_pchat_get_deleted_message_ids( $project_id ),
        'artist_can_attach' => (bool) rmbz_pchat_get_artist_can_attach( $project_id ),
        'chat_locked'       => rmbz_pchat_is_chat_locked( $project_id ),
        'server_time'       => current_time( 'mysql' ),
        'server_timestamp_ms' => time() * 1000,
    ] );
}

function rmbz_pchat_artist_rest_info( WP_REST_Request $req ) {
    $project_id = (int) $req['id'];
    $own = rmbz_pchat_artist_own_project( $project_id, $req );
    if ( is_wp_error( $own ) ) {
        return rmbz_api_error( $own->get_error_message(), (int) ( $own->get_error_data()['status'] ?? 400 ), $own->get_error_code() );
    }

    return rmbz_api_ok( [
        'artist_can_attach' => (bool) rmbz_pchat_get_artist_can_attach( $project_id ),
        'chat_locked'       => rmbz_pchat_is_chat_locked( $project_id ),
        'server_time'       => current_time( 'mysql' ),
    ] );
}

/** Estado live de todos os projetos do artista, numa unica consulta leve. */
function rmbz_pchat_artist_rest_filming_statuses( WP_REST_Request $req ) {
    $tel = (string) $req->get_param( 'rmbz_telemovel' );
    if ( $tel === '' ) return rmbz_api_error( 'Sessao expirada.', 401, 'not_logged_in' );
    global $wpdb;
    $rows = $wpdb->get_results( $wpdb->prepare(
        "SELECT id, extra_data FROM {$wpdb->prefix}rmbz_artist_projects WHERE artist_telemovel = %s AND production_status = 'filming' ORDER BY id DESC",
        $tel
    ) );
    $active_project_id = 0;
    $active = null;
    foreach ( (array) $rows as $row ) {
        $extra = ! empty( $row->extra_data ) ? json_decode( (string) $row->extra_data, true ) : [];
        if ( ! is_array( $extra ) ) continue;
        $sessions = isset( $extra['filming_sessions'] ) && is_array( $extra['filming_sessions'] )
            ? $extra['filming_sessions'] : [];
        foreach ( $sessions as $session ) {
            if ( is_array( $session ) && empty( $session['ended_at'] ) ) {
                $active_project_id = (int) $row->id;
                $active = $session;
                break 2;
            }
        }
    }

    return rmbz_api_ok( [
        'active_project_id' => $active_project_id,
        'active'            => is_array( $active ),
        'day'               => is_array( $active ) ? (int) ( $active['day'] ?? 1 ) : 0,
        'started_ts'        => is_array( $active ) ? (int) ( $active['started_ts'] ?? 0 ) : 0,
        'server_timestamp'  => (int) current_time( 'timestamp', true ),
    ] );
}

function rmbz_pchat_artist_rest_send( WP_REST_Request $req ) {
    $project_id = (int) $req['id'];
    $own = rmbz_pchat_artist_own_project( $project_id, $req );
    if ( is_wp_error( $own ) ) {
        return rmbz_api_error( $own->get_error_message(), (int) ( $own->get_error_data()['status'] ?? 400 ), $own->get_error_code() );
    }

    // Bloquear envio se o projeto morreu (rejeitado ou cancelado por prazo).
    if ( rmbz_pchat_is_chat_locked( $project_id ) ) {
        return rmbz_api_error( 'Chat desativado — o projeto foi cancelado ou rejeitado.', 403, 'project_locked' );
    }

    $body_json = $req->get_json_params();
    $text = isset( $body_json['body'] ) ? (string) $body_json['body'] : '';
    $text = sanitize_textarea_field( $text );

    $attachment = null;
    if ( ! empty( $body_json['attachment'] ) && is_array( $body_json['attachment'] ) ) {
        // Re-validar: artista só pode anexar se admin permitiu
        if ( ! rmbz_pchat_get_artist_can_attach( $project_id ) ) {
            return rmbz_api_error( 'Anexos do artista não estão habilitados neste projeto.', 403, 'attach_disabled' );
        }
        $a = $body_json['attachment'];
        if ( ! empty( $a['url'] ) ) {
            // Validar que o URL é da nossa pasta de uploads (anti-injecção)
            $uploads = wp_upload_dir();
            $allowed_prefix = trailingslashit( $uploads['baseurl'] ) . '1mz-chat/' . $project_id . '/';
            if ( strpos( (string) $a['url'], $allowed_prefix ) !== 0 ) {
                return rmbz_api_error( 'URL de anexo inválido.', 400, 'bad_url' );
            }
            $attachment = [
                'url'  => esc_url_raw( (string) $a['url'] ),
                'type' => sanitize_key( (string) ( $a['type'] ?? 'file' ) ),
                'name' => sanitize_text_field( (string) ( $a['name'] ?? '' ) ),
                'size' => (int) ( $a['size'] ?? 0 ),
            ];
        }
    }

    if ( $text === '' && empty( $attachment ) ) {
        return rmbz_api_error( 'Mensagem vazia.', 400, 'empty' );
    }

    $msg_id = rmbz_pchat_insert_message_as_artist( $project_id, $text, $attachment );
    if ( ! $msg_id ) {
        return rmbz_api_error( 'Falha ao gravar mensagem.', 500, 'insert_fail' );
    }

    return rmbz_api_ok( [
        'id'       => $msg_id,
        'messages' => rmbz_pchat_artist_prepare_messages( rmbz_pchat_get_messages( $project_id, $msg_id - 1 ) ),
        'server_timestamp_ms' => time() * 1000,
    ] );
}

function rmbz_pchat_artist_rest_upload( WP_REST_Request $req ) {
    $project_id = (int) $req['id'];
    $own = rmbz_pchat_artist_own_project( $project_id, $req );
    if ( is_wp_error( $own ) ) {
        return rmbz_api_error( $own->get_error_message(), (int) ( $own->get_error_data()['status'] ?? 400 ), $own->get_error_code() );
    }

    // Toggle obrigatório
    if ( ! rmbz_pchat_get_artist_can_attach( $project_id ) ) {
        return rmbz_api_error( 'Anexos não estão habilitados neste projeto.', 403, 'attach_disabled' );
    }
    if ( empty( $_FILES['file'] ) ) {
        return rmbz_api_error( 'Sem ficheiro recebido.', 400, 'no_file' );
    }
    $res = rmbz_pchat_handle_upload( $project_id, $_FILES['file'], 'artist' );
    if ( is_wp_error( $res ) ) {
        return rmbz_api_error( $res->get_error_message(), 400, $res->get_error_code() );
    }
    return rmbz_api_ok( $res );
}

function rmbz_pchat_artist_rest_delete( WP_REST_Request $req ) {
    $project_id = (int) $req['id'];
    $own = rmbz_pchat_artist_own_project( $project_id, $req );
    if ( is_wp_error( $own ) ) {
        return rmbz_api_error( $own->get_error_message(), (int) ( $own->get_error_data()['status'] ?? 400 ), $own->get_error_code() );
    }

    $body_json = $req->get_json_params();
    $msg_id = (int) ( $body_json['message_id'] ?? 0 );
    if ( $msg_id <= 0 ) {
        return rmbz_api_error( 'ID de mensagem inválido.', 400, 'bad_id' );
    }

    global $wpdb;
    $row = $wpdb->get_row( $wpdb->prepare(
        "SELECT * FROM {$wpdb->prefix}rmbz_project_chat_messages
         WHERE id = %d AND project_id = %d",
        $msg_id,
        $project_id
    ) );
    if ( ! $row ) {
        return rmbz_api_error( 'Mensagem não encontrada.', 404, 'not_found' );
    }
    if ( $row->author_type !== 'artist' ) {
        return rmbz_api_error( 'Só podes apagar as tuas próprias mensagens.', 403, 'forbidden' );
    }
    if ( ! empty( $row->is_deleted ) ) {
        return rmbz_api_ok( [ 'id' => $msg_id, 'deleted' => true ] );
    }

    $created = DateTimeImmutable::createFromFormat( 'Y-m-d H:i:s', (string) $row->created_at, wp_timezone() );
    if ( ! $created || time() > $created->getTimestamp() + 120 ) {
        return rmbz_api_error( 'O prazo de 2 minutos para apagar esta mensagem terminou.', 403, 'delete_window_expired' );
    }

    $updated = $wpdb->update(
        $wpdb->prefix . 'rmbz_project_chat_messages',
        [ 'is_deleted' => 1, 'attachment_url' => null, 'edited_at' => current_time( 'mysql' ) ],
        [ 'id' => $msg_id, 'project_id' => $project_id ],
        [ '%d', '%s', '%s' ],
        [ '%d', '%d' ]
    );
    if ( $updated === false ) {
        return rmbz_api_error( 'Não foi possível apagar a mensagem.', 500, 'delete_failed' );
    }

    delete_transient( 'rmbz_admin_notification_counts' );
    return rmbz_api_ok( [ 'id' => $msg_id, 'deleted' => true ] );
}

/* ============================================================================
 * Insert variant para artist: espelha no legado + push para admin
 * ============================================================================
 *
 * O rmbz_pchat_insert_message() existente espelha admin → legado. Aqui
 * fazemos artist → legado (mesmo formato, autor diferente) para que a UI
 * antiga em qualquer página do plugin continue a ver as mensagens
 * mesmo sem migração.
 */
function rmbz_pchat_insert_message_as_artist( $project_id, $body, $attachment = null ) {
    global $wpdb;
    $project_id = (int) $project_id;

    $body = (string) $body;
    $att_url  = isset( $attachment['url'] )  ? (string) $attachment['url']  : null;
    $att_type = isset( $attachment['type'] ) ? (string) $attachment['type'] : null;
    $att_name = isset( $attachment['name'] ) ? (string) $attachment['name'] : null;
    $att_size = isset( $attachment['size'] ) ? (int) $attachment['size']    : null;

    if ( trim( $body ) === '' && empty( $att_url ) ) {
        return false;
    }

    $ok = $wpdb->insert(
        $wpdb->prefix . 'rmbz_project_chat_messages',
        [
            'project_id'      => $project_id,
            'author_type'     => 'artist',
            'author_label'    => 'Artista',
            'body'            => $body,
            'attachment_url'  => $att_url,
            'attachment_type' => $att_type,
            'attachment_name' => $att_name,
            'attachment_size' => $att_size,
            'read_by_admin'   => 0,
            'read_by_artist'  => 1,
            'created_at'      => current_time( 'mysql' ),
        ],
        [ '%d','%s','%s','%s','%s','%s','%s','%d','%d','%d','%s' ]
    );
    if ( ! $ok ) return false;
    $msg_id = (int) $wpdb->insert_id;

    // Espelhar no legado artist_feedback (mantém compat com UI antiga e app)
    $ts = current_time( 'd/m/Y H:i' );
    $synth = "[$ts] <strong>Artista:</strong> ";
    if ( $body !== '' ) $synth .= $body;
    if ( $att_url ) {
        if ( $body !== '' ) $synth .= "\n";
        $synth .= '📎 ' . ( $att_name ?: 'Anexo' ) . ' — ' . esc_url_raw( $att_url );
    }
    $proj = $wpdb->get_row( $wpdb->prepare(
        "SELECT artist_feedback FROM {$wpdb->prefix}rmbz_artist_projects WHERE id = %d",
        $project_id
    ) );
    if ( $proj ) {
        $updated = trim( (string) $proj->artist_feedback );
        $updated = $updated === '' ? $synth : $updated . "\n\n" . $synth;
        $wpdb->update(
            $wpdb->prefix . 'rmbz_artist_projects',
            [ 'artist_feedback' => $updated ],
            [ 'id' => $project_id ],
            [ '%s' ], [ '%d' ]
        );
    }

    // [1.5.200] Invalidar cache do badge do menu admin para o contador
    // de "Mensagens novas" aparecer no próximo refresh do dashboard sem
    // ter de esperar pelos 2 minutos do transient.
    delete_transient( 'rmbz_admin_notification_counts' );

    // Push para o admin? Não pedido pelo Jaime — admin vê pelo badge no
    // menu do WP admin e pela bolha vermelha no card do projeto.

    return $msg_id;
}
