//! RPC API endpoints.
//!
//! REST endpoints for blockchain RPC operations:
//! - Block queries
//! - Transaction submission and queries
//! - Network information
//! - Chain state

use axum::{
    extract::{Path, Query, State},
    routing::{get, post},
    Json, Router,
};
use serde::{Deserialize, Serialize};

use crate::{
    auth::{require_permission, Authenticated},
    error::ApiResult,
    response::{ApiResponse, PaginationParams},
    routes::AppState,
};

/// Build RPC routes.
pub fn router() -> Router<AppState> {
    Router::new()
        // Block operations
        .route("/block/:id", get(get_block))
        .route("/blocks", get(get_blocks))
        .route("/tips", get(get_tips))
        .route("/block-count", get(get_block_count))
        // Transaction operations
        .route("/tx/:txid", get(get_transaction))
        .route("/tx/send", post(send_transaction))
        .route("/tx/estimate-fee", post(estimate_fee))
        .route("/mempool", get(get_mempool))
        // Network info
        .route("/info", get(get_network_info))
        .route("/peers", get(get_peers))
        .route("/sync-status", get(get_sync_status))
        // Mining (for miners)
        .route("/mining/template", get(get_block_template))
        .route("/mining/submit", post(submit_block))
}

// ============================================================================
// Types
// ============================================================================

#[derive(Debug, Serialize, Deserialize)]
pub struct BlockResponse {
    pub hash: String,
    pub height: u64,
    pub timestamp: u64,
    pub parent_hashes: Vec<String>,
    pub transactions: Vec<String>,
    pub blue_score: u64,
    pub difficulty: String,
    pub nonce: u64,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct TransactionResponse {
    pub txid: String,
    pub version: u32,
    pub inputs: Vec<TxInput>,
    pub outputs: Vec<TxOutput>,
    pub lock_time: u64,
    pub mass: u64,
    pub block_hash: Option<String>,
    pub confirmations: u64,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct TxInput {
    pub previous_outpoint: String,
    pub signature_script: String,
    pub sequence: u64,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct TxOutput {
    pub value: String,
    pub script_public_key: String,
}

#[derive(Debug, Deserialize)]
pub struct SendTransactionRequest {
    pub raw_tx: String,
}

#[derive(Debug, Serialize)]
pub struct SendTransactionResponse {
    pub txid: String,
    pub accepted: bool,
}

#[derive(Debug, Deserialize)]
pub struct EstimateFeeRequest {
    pub priority: String, // low, medium, high
    pub tx_size: Option<u32>,
}

#[derive(Debug, Serialize)]
pub struct FeeEstimate {
    pub priority: String,
    pub fee_per_mass: String,
    pub estimated_fee: String,
}

#[derive(Debug, Serialize)]
pub struct NetworkInfo {
    pub version: String,
    pub protocol_version: u32,
    pub network: String,
    pub connections: u32,
    pub block_count: u64,
    pub difficulty: String,
    pub hashrate: String,
    pub mempool_size: u32,
    pub synced: bool,
}

#[derive(Debug, Serialize)]
pub struct SyncStatus {
    pub synced: bool,
    pub current_height: u64,
    pub target_height: u64,
    pub progress: f64,
    pub estimated_time_remaining: Option<u64>,
}

#[derive(Debug, Serialize)]
pub struct BlockTemplate {
    pub parent_hashes: Vec<String>,
    pub transactions: Vec<String>,
    pub coinbase_value: String,
    pub coinbase_script: String,
    pub bits: String,
    pub target: String,
    pub timestamp: u64,
}

#[derive(Debug, Deserialize)]
pub struct SubmitBlockRequest {
    pub header: String,
    pub transactions: Vec<String>,
}

// ============================================================================
// Handlers
// ============================================================================

async fn get_block(
    State(state): State<AppState>,
    Authenticated(auth): Authenticated,
    Path(id): Path<String>,
) -> ApiResult<Json<ApiResponse<BlockResponse>>> {
    require_permission(&auth, "read")?;

    // In production, query the RPC service
    let block = BlockResponse {
        hash: id.clone(),
        height: 100000,
        timestamp: 1705312200,
        parent_hashes: vec!["parent1...".to_string()],
        transactions: vec!["tx1...".to_string(), "tx2...".to_string()],
        blue_score: 50000,
        difficulty: "1234567890".to_string(),
        nonce: 12345,
    };

    Ok(Json(ApiResponse::success(block)))
}

async fn get_blocks(
    State(state): State<AppState>,
    Authenticated(auth): Authenticated,
    Query(pagination): Query<PaginationParams>,
) -> ApiResult<Json<ApiResponse<Vec<BlockResponse>>>> {
    require_permission(&auth, "read")?;

    // Return latest blocks
    let blocks = vec![]; // Placeholder
    let meta = pagination.to_meta(0);

    Ok(Json(ApiResponse::success_paginated(blocks, meta)))
}

async fn get_tips(
    State(state): State<AppState>,
    Authenticated(auth): Authenticated,
) -> ApiResult<Json<ApiResponse<Vec<String>>>> {
    require_permission(&auth, "read")?;

    let tips = vec!["tip1...".to_string(), "tip2...".to_string()];
    Ok(Json(ApiResponse::success(tips)))
}

async fn get_block_count(
    State(state): State<AppState>,
    Authenticated(auth): Authenticated,
) -> ApiResult<Json<ApiResponse<serde_json::Value>>> {
    require_permission(&auth, "read")?;

    let count = serde_json::json!({
        "block_count": 100000,
        "header_count": 100000
    });

    Ok(Json(ApiResponse::success(count)))
}

async fn get_transaction(
    State(state): State<AppState>,
    Authenticated(auth): Authenticated,
    Path(txid): Path<String>,
) -> ApiResult<Json<ApiResponse<TransactionResponse>>> {
    require_permission(&auth, "read")?;

    let tx = TransactionResponse {
        txid,
        version: 1,
        inputs: vec![],
        outputs: vec![],
        lock_time: 0,
        mass: 1000,
        block_hash: Some("blockhash...".to_string()),
        confirmations: 10,
    };

    Ok(Json(ApiResponse::success(tx)))
}

async fn send_transaction(
    State(state): State<AppState>,
    Authenticated(auth): Authenticated,
    Json(req): Json<SendTransactionRequest>,
) -> ApiResult<Json<ApiResponse<SendTransactionResponse>>> {
    require_permission(&auth, "write")?;

    // In production, broadcast to network
    let response = SendTransactionResponse {
        txid: "newtxid...".to_string(),
        accepted: true,
    };

    Ok(Json(ApiResponse::success(response)))
}

async fn estimate_fee(
    State(state): State<AppState>,
    Authenticated(auth): Authenticated,
    Json(req): Json<EstimateFeeRequest>,
) -> ApiResult<Json<ApiResponse<FeeEstimate>>> {
    require_permission(&auth, "read")?;

    let estimate = FeeEstimate {
        priority: req.priority,
        fee_per_mass: "1".to_string(),
        estimated_fee: "1000".to_string(),
    };

    Ok(Json(ApiResponse::success(estimate)))
}

async fn get_mempool(
    State(state): State<AppState>,
    Authenticated(auth): Authenticated,
    Query(pagination): Query<PaginationParams>,
) -> ApiResult<Json<ApiResponse<Vec<String>>>> {
    require_permission(&auth, "read")?;

    let txids = vec!["mempool_tx1...".to_string()];
    let meta = pagination.to_meta(1);

    Ok(Json(ApiResponse::success_paginated(txids, meta)))
}

async fn get_network_info(
    State(state): State<AppState>,
    Authenticated(auth): Authenticated,
) -> ApiResult<Json<ApiResponse<NetworkInfo>>> {
    require_permission(&auth, "read")?;

    let info = NetworkInfo {
        version: "0.1.0".to_string(),
        protocol_version: 1,
        network: "mainnet".to_string(),
        connections: 50,
        block_count: 100000,
        difficulty: "1234567890".to_string(),
        hashrate: "100 TH/s".to_string(),
        mempool_size: 100,
        synced: true,
    };

    Ok(Json(ApiResponse::success(info)))
}

async fn get_peers(
    State(state): State<AppState>,
    Authenticated(auth): Authenticated,
) -> ApiResult<Json<ApiResponse<Vec<serde_json::Value>>>> {
    require_permission(&auth, "read")?;

    let peers = vec![
        serde_json::json!({
            "id": "peer1",
            "address": "192.168.1.1:16100",
            "connected_since": 1705312200
        })
    ];

    Ok(Json(ApiResponse::success(peers)))
}

async fn get_sync_status(
    State(state): State<AppState>,
    Authenticated(auth): Authenticated,
) -> ApiResult<Json<ApiResponse<SyncStatus>>> {
    require_permission(&auth, "read")?;

    let status = SyncStatus {
        synced: true,
        current_height: 100000,
        target_height: 100000,
        progress: 100.0,
        estimated_time_remaining: None,
    };

    Ok(Json(ApiResponse::success(status)))
}

async fn get_block_template(
    State(state): State<AppState>,
    Authenticated(auth): Authenticated,
) -> ApiResult<Json<ApiResponse<BlockTemplate>>> {
    require_permission(&auth, "read")?;

    let template = BlockTemplate {
        parent_hashes: vec!["parent...".to_string()],
        transactions: vec![],
        coinbase_value: "50000000000".to_string(),
        coinbase_script: "".to_string(),
        bits: "1d00ffff".to_string(),
        target: "00000000ffff...".to_string(),
        timestamp: 1705312200,
    };

    Ok(Json(ApiResponse::success(template)))
}

async fn submit_block(
    State(state): State<AppState>,
    Authenticated(auth): Authenticated,
    Json(req): Json<SubmitBlockRequest>,
) -> ApiResult<Json<ApiResponse<serde_json::Value>>> {
    require_permission(&auth, "write")?;

    let result = serde_json::json!({
        "accepted": true,
        "block_hash": "newblockhash..."
    });

    Ok(Json(ApiResponse::success(result)))
}
