//! Storage API endpoints.
//!
//! REST endpoints for decentralized storage operations:
//! - File upload/download
//! - Pinning management
//! - CAR file operations
//! - Directory management

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

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

/// Build storage routes.
pub fn router() -> Router<AppState> {
    Router::new()
        // Upload/Download
        .route("/upload", post(upload_file))
        .route("/download/:cid", get(download_file))
        .route("/gateway/:cid", get(gateway_url))
        // Pinning
        .route("/pin/:cid", post(pin_content))
        .route("/pin/:cid", delete(unpin_content))
        .route("/pin/:cid/status", get(pin_status))
        .route("/pins", get(list_pins))
        // CAR files
        .route("/car/create", post(create_car))
        .route("/car/import", post(import_car))
        // Directories
        .route("/directory", post(create_directory))
        .route("/directory/:cid", get(list_directory))
}

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

#[derive(Debug, Serialize)]
pub struct UploadResponse {
    pub cid: String,
    pub size: u64,
    pub gateway_url: String,
}

#[derive(Debug, Serialize)]
pub struct PinStatus {
    pub cid: String,
    pub pinned: bool,
    pub size: u64,
    pub created_at: String,
    pub expires_at: Option<String>,
}

#[derive(Debug, Deserialize)]
pub struct PinRequest {
    pub duration_days: Option<u32>,
}

#[derive(Debug, Serialize)]
pub struct DirectoryEntry {
    pub name: String,
    pub cid: String,
    pub size: u64,
    pub is_directory: bool,
}

#[derive(Debug, Deserialize)]
pub struct CreateDirectoryRequest {
    pub files: Vec<FileEntry>,
}

#[derive(Debug, Deserialize)]
pub struct FileEntry {
    pub name: String,
    pub cid: String,
}

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

async fn upload_file(
    State(state): State<AppState>,
    Authenticated(auth): Authenticated,
    multipart: Multipart,
) -> ApiResult<Json<ApiResponse<UploadResponse>>> {
    require_permission(&auth, "write")?;

    // In production, process multipart upload
    let response = UploadResponse {
        cid: "bafybeigdyr...".to_string(),
        size: 1024,
        gateway_url: "https://gateway.synor.io/ipfs/bafybeigdyr...".to_string(),
    };

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

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

    // In production, return file content or redirect to gateway
    let result = serde_json::json!({
        "cid": cid,
        "gateway_url": format!("https://gateway.synor.io/ipfs/{}", cid)
    });

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

async fn gateway_url(
    State(state): State<AppState>,
    Path(cid): Path<String>,
) -> ApiResult<Json<ApiResponse<serde_json::Value>>> {
    let url = serde_json::json!({
        "url": format!("https://gateway.synor.io/ipfs/{}", cid)
    });

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

async fn pin_content(
    State(state): State<AppState>,
    Authenticated(auth): Authenticated,
    Path(cid): Path<String>,
    Json(req): Json<PinRequest>,
) -> ApiResult<Json<ApiResponse<PinStatus>>> {
    require_permission(&auth, "write")?;

    let status = PinStatus {
        cid,
        pinned: true,
        size: 1024,
        created_at: "2024-01-15T10:30:00Z".to_string(),
        expires_at: req.duration_days.map(|d| format!("in {} days", d)),
    };

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

async fn unpin_content(
    State(state): State<AppState>,
    Authenticated(auth): Authenticated,
    Path(cid): Path<String>,
) -> ApiResult<Json<ApiResponse<serde_json::Value>>> {
    require_permission(&auth, "delete")?;

    let result = serde_json::json!({
        "cid": cid,
        "unpinned": true
    });

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

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

    let status = PinStatus {
        cid,
        pinned: true,
        size: 1024,
        created_at: "2024-01-15T10:30:00Z".to_string(),
        expires_at: None,
    };

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

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

    let pins = vec![];
    let meta = pagination.to_meta(0);

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

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

    let result = serde_json::json!({
        "car_cid": "bafycar...",
        "root_cid": "bafyroot...",
        "size": 2048
    });

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

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

    let cids = vec!["bafycid1...".to_string(), "bafycid2...".to_string()];
    Ok(Json(ApiResponse::success(cids)))
}

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

    let result = serde_json::json!({
        "cid": "bafydir...",
        "file_count": req.files.len()
    });

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

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

    let entries = vec![
        DirectoryEntry {
            name: "file1.txt".to_string(),
            cid: "bafyfile1...".to_string(),
            size: 1024,
            is_directory: false,
        },
    ];

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