use axum::Extension;
use axum::extract::{FromRef, Path, Query, State};
use axum::response::Json;
use chrono::Utc;
use sea_orm::{
    ActiveModelTrait, ColumnTrait, EntityTrait, PaginatorTrait, QueryFilter, QueryOrder, Set,
    prelude::Decimal,
};
use uuid::Uuid;

use erp_core::error::AppError;
use erp_core::rbac::require_permission;
use erp_core::types::{ApiResponse, PaginatedResponse, TenantContext};

use crate::data_dto::{
    MarketEntryDetailResp, MarketEntryResp, MarketListParams, MarketReviewResp, SubmitReviewReq,
};
use crate::entity::{market_entry, market_review, plugin};
use crate::state::PluginState;

fn entry_to_resp(model: &market_entry::Model) -> MarketEntryResp {
    MarketEntryResp {
        id: model.id.to_string(),
        plugin_id: model.plugin_id.clone(),
        name: model.name.clone(),
        version: model.version.clone(),
        description: model.description.clone(),
        author: model.author.clone(),
        category: model.category.clone(),
        tags: model.tags.clone(),
        icon_url: model.icon_url.clone(),
        screenshots: model.screenshots.clone(),
        min_platform_version: model.min_platform_version.clone(),
        status: model.status.clone(),
        download_count: model.download_count,
        rating_avg: model.rating_avg.to_string().parse().unwrap_or(0.0),
        rating_count: model.rating_count,
        changelog: model.changelog.clone(),
        created_at: Some(model.created_at),
        updated_at: Some(model.updated_at),
    }
}

#[utoipa::path(
    get,
    path = "/api/v1/market/entries",
    params(MarketListParams),
    responses(
        (status = 200, description = "市场条目列表", body = ApiResponse<PaginatedResponse<MarketEntryResp>>)
    ),
    tag = "Plugin Market",
)]
pub async fn list_market_entries<S>(
    State(_state): State<S>,
    Query(params): Query<MarketListParams>,
    Extension(ctx): Extension<TenantContext>,
) -> Result<Json<ApiResponse<PaginatedResponse<MarketEntryResp>>>, AppError>
where
    PluginState: FromRef<S>,
    S: Clone + Send + Sync + 'static,
{
    require_permission(&ctx, "plugin.admin")?;

    let state: PluginState = PluginState::from_ref(&_state);
    let db = &state.db;

    let page = params.page.unwrap_or(1);
    let page_size = params.page_size.unwrap_or(20).min(100);

    let mut query =
        market_entry::Entity::find().filter(market_entry::Column::Status.eq("published"));

    if let Some(ref category) = params.category {
        query = query.filter(market_entry::Column::Category.eq(category.as_str()));
    }

    if let Some(ref search) = params.search {
        query = query.filter(
            sea_orm::Condition::any()
                .add(market_entry::Column::Name.contains(search.as_str()))
                .add(market_entry::Column::Description.contains(search.as_str()))
                .add(market_entry::Column::Author.contains(search.as_str())),
        );
    }

    query = query.order_by_desc(market_entry::Column::DownloadCount);

    let total = query
        .clone()
        .count(db)
        .await
        .map_err(|e| AppError::Internal(e.to_string()))?;
    let total_pages = ((total as f64) / (page_size as f64)).ceil() as u64;

    let models = query
        .paginate(db, page_size)
        .fetch_page(page.saturating_sub(1))
        .await
        .map_err(|e| AppError::Internal(e.to_string()))?;

    let items = models.iter().map(entry_to_resp).collect();

    Ok(Json(ApiResponse::ok(PaginatedResponse {
        data: items,
        total,
        page,
        page_size,
        total_pages,
    })))
}

#[utoipa::path(
    get,
    path = "/api/v1/market/entries/{id}",
    responses(
        (status = 200, description = "市场条目详情", body = ApiResponse<MarketEntryDetailResp>)
    ),
    tag = "Plugin Market",
)]
pub async fn get_market_entry<S>(
    State(_state): State<S>,
    Path(id): Path<Uuid>,
    Extension(ctx): Extension<TenantContext>,
) -> Result<Json<ApiResponse<MarketEntryDetailResp>>, AppError>
where
    PluginState: FromRef<S>,
    S: Clone + Send + Sync + 'static,
{
    require_permission(&ctx, "plugin.admin")?;

    let state: PluginState = PluginState::from_ref(&_state);
    let db = &state.db;

    let model = market_entry::Entity::find_by_id(id)
        .one(db)
        .await
        .map_err(|e| AppError::Internal(e.to_string()))?
        .ok_or_else(|| AppError::NotFound("市场条目不存在".to_string()))?;

    // 解析 manifest 检查依赖
    let mut dependency_warnings = Vec::new();
    if let Ok(manifest) = crate::manifest::parse_manifest(&model.manifest_toml) {
        for dep_id in &manifest.metadata.dependencies {
            let installed = plugin::Entity::find()
                .filter(plugin::Column::Name.eq(dep_id.as_str()))
                .one(db)
                .await
                .map_err(|e| AppError::Internal(e.to_string()))?;
            if installed.is_none() {
                dependency_warnings.push(format!("依赖插件 '{}' 尚未安装", dep_id));
            }
        }
    }

    Ok(Json(ApiResponse::ok(MarketEntryDetailResp {
        entry: entry_to_resp(&model),
        dependency_warnings,
    })))
}

#[utoipa::path(
    post,
    path = "/api/v1/market/entries/{id}/install",
    responses(
        (status = 200, description = "从市场安装插件", body = ApiResponse<crate::dto::PluginResp>)
    ),
    tag = "Plugin Market",
)]
pub async fn install_from_market<S>(
    State(_state): State<S>,
    Path(id): Path<Uuid>,
    Extension(ctx): Extension<TenantContext>,
) -> Result<Json<ApiResponse<crate::dto::PluginResp>>, AppError>
where
    PluginState: FromRef<S>,
    S: Clone + Send + Sync + 'static,
{
    require_permission(&ctx, "plugin.admin")?;

    let state: PluginState = PluginState::from_ref(&_state);
    let db = &state.db;
    let engine = &state.engine;

    // 获取市场条目
    let market_model = market_entry::Entity::find_by_id(id)
        .one(db)
        .await
        .map_err(|e| AppError::Internal(e.to_string()))?
        .ok_or_else(|| AppError::NotFound("市场条目不存在".to_string()))?;

    if market_model.status != "published" {
        return Err(AppError::Validation("该插件已下架，无法安装".to_string()));
    }

    // 检查是否已安装同 plugin_id 的插件
    let existing = plugin::Entity::find()
        .filter(plugin::Column::Name.eq(market_model.plugin_id.as_str()))
        .filter(plugin::Column::TenantId.eq(ctx.tenant_id))
        .one(db)
        .await
        .map_err(|e| AppError::Internal(e.to_string()))?;

    if existing.is_some() {
        return Err(AppError::Validation(
            "该插件已安装，如需更新请使用升级功能".to_string(),
        ));
    }

    // upload → install → enable 一条龙
    let wasm_binary = market_model.wasm_binary.clone();
    let manifest_toml = market_model.manifest_toml.clone();

    let plugin_resp = crate::service::PluginService::upload(
        ctx.tenant_id,
        ctx.user_id,
        wasm_binary,
        &manifest_toml,
        db,
    )
    .await?;

    let plugin_id = plugin_resp.id;
    let _plugin_resp =
        crate::service::PluginService::install(plugin_id, ctx.tenant_id, ctx.user_id, db, engine)
            .await?;

    let plugin_resp =
        crate::service::PluginService::enable(plugin_id, ctx.tenant_id, ctx.user_id, db, engine)
            .await?;

    // 递增下载计数
    let mut active: market_entry::ActiveModel = market_model.into();
    let current = active.download_count.take().unwrap_or(0);
    active.download_count = Set(current + 1);
    let _ = active
        .update(db)
        .await
        .map_err(|e| AppError::Internal(e.to_string()))?;

    Ok(Json(ApiResponse::ok(plugin_resp)))
}

#[utoipa::path(
    get,
    path = "/api/v1/market/entries/{id}/reviews",
    responses(
        (status = 200, description = "评论列表", body = ApiResponse<Vec<MarketReviewResp>>)
    ),
    tag = "Plugin Market",
)]
pub async fn list_market_reviews<S>(
    State(_state): State<S>,
    Path(id): Path<Uuid>,
    Extension(ctx): Extension<TenantContext>,
) -> Result<Json<ApiResponse<Vec<MarketReviewResp>>>, AppError>
where
    PluginState: FromRef<S>,
    S: Clone + Send + Sync + 'static,
{
    require_permission(&ctx, "plugin.admin")?;

    let state: PluginState = PluginState::from_ref(&_state);
    let db = &state.db;

    let reviews = market_review::Entity::find()
        .filter(market_review::Column::MarketEntryId.eq(id))
        .all(db)
        .await
        .map_err(|e| AppError::Internal(e.to_string()))?;

    let items = reviews
        .iter()
        .map(|r| MarketReviewResp {
            id: r.id.to_string(),
            user_id: r.user_id.to_string(),
            market_entry_id: r.market_entry_id.to_string(),
            rating: r.rating,
            review_text: r.review_text.clone(),
            created_at: Some(r.created_at),
        })
        .collect();

    Ok(Json(ApiResponse::ok(items)))
}

#[utoipa::path(
    post,
    path = "/api/v1/market/entries/{id}/reviews",
    responses(
        (status = 200, description = "提交评分/评论", body = ApiResponse<MarketReviewResp>)
    ),
    tag = "Plugin Market",
)]
pub async fn submit_market_review<S>(
    State(_state): State<S>,
    Path(id): Path<Uuid>,
    Extension(ctx): Extension<TenantContext>,
    Json(body): Json<SubmitReviewReq>,
) -> Result<Json<ApiResponse<MarketReviewResp>>, AppError>
where
    PluginState: FromRef<S>,
    S: Clone + Send + Sync + 'static,
{
    require_permission(&ctx, "plugin.admin")?;

    if body.rating < 1 || body.rating > 5 {
        return Err(AppError::Validation("评分必须在 1-5 之间".to_string()));
    }

    let state: PluginState = PluginState::from_ref(&_state);
    let db = &state.db;

    // 验证市场条目存在
    let entry_model = market_entry::Entity::find_by_id(id)
        .one(db)
        .await
        .map_err(|e| AppError::Internal(e.to_string()))?
        .ok_or_else(|| AppError::NotFound("市场条目不存在".to_string()))?;

    // upsert: 同一用户同一条目只保留最新评论
    let existing = market_review::Entity::find()
        .filter(market_review::Column::MarketEntryId.eq(id))
        .filter(market_review::Column::UserId.eq(ctx.user_id))
        .filter(market_review::Column::TenantId.eq(ctx.tenant_id))
        .one(db)
        .await
        .map_err(|e| AppError::Internal(e.to_string()))?;

    let review_model = if let Some(existing) = existing {
        let mut active: market_review::ActiveModel = existing.into();
        active.rating = Set(body.rating);
        active.review_text = Set(body.review_text);
        active
            .update(db)
            .await
            .map_err(|e| AppError::Internal(e.to_string()))?
    } else {
        let review_id = Uuid::now_v7();
        let now = Utc::now();
        let model = market_review::ActiveModel {
            id: Set(review_id),
            tenant_id: Set(ctx.tenant_id),
            user_id: Set(ctx.user_id),
            market_entry_id: Set(id),
            rating: Set(body.rating),
            review_text: Set(body.review_text),
            created_at: Set(now),
        };
        model
            .insert(db)
            .await
            .map_err(|e| AppError::Internal(e.to_string()))?
    };

    // 重新计算平均评分
    let all_reviews = market_review::Entity::find()
        .filter(market_review::Column::MarketEntryId.eq(id))
        .all(db)
        .await
        .map_err(|e| AppError::Internal(e.to_string()))?;

    let count = all_reviews.len() as i32;
    let avg: f64 = if count > 0 {
        all_reviews.iter().map(|r| r.rating as f64).sum::<f64>() / count as f64
    } else {
        0.0
    };

    let mut entry_active: market_entry::ActiveModel = entry_model.into();
    let avg_decimal = Decimal::from_f64_retain(avg).unwrap_or_default();
    entry_active.rating_avg = Set(avg_decimal);
    entry_active.rating_count = Set(count);
    let _ = entry_active
        .update(db)
        .await
        .map_err(|e| AppError::Internal(e.to_string()))?;

    Ok(Json(ApiResponse::ok(MarketReviewResp {
        id: review_model.id.to_string(),
        user_id: review_model.user_id.to_string(),
        market_entry_id: review_model.market_entry_id.to_string(),
        rating: review_model.rating,
        review_text: review_model.review_text,
        created_at: Some(review_model.created_at),
    })))
}
