#![allow(dead_code)]
#![allow(unused_imports)]
#![allow(clippy::redundant_closure)]
#![allow(clippy::useless_conversion)]
#![allow(clippy::clone_on_copy)]
use axum::{
    extract::{Path, State},
    http::StatusCode,
    response::IntoResponse,
    Extension, Json,
};
use mongodb::bson::oid::ObjectId;
use serde::{Deserialize, Serialize};
use validator::Validate;

use crate::{
    auth::jwt::Claims,
    config::AppState,
    models::{permission::Permission, share::Share},
};

#[derive(Debug, Deserialize, Validate)]
pub struct CreateShareRequest {
    pub target_user_email: String,
    pub resource_type: String,
    pub resource_id: Option<String>,
    pub permissions: Vec<String>,
    #[serde(default)]
    pub expires_days: Option<u64>,
}

#[derive(Debug, Serialize)]
pub struct ShareResponse {
    pub id: String,
    pub target_user_id: String,
    pub resource_type: String,
    pub resource_id: Option<String>,
    pub permissions: Vec<String>,
    pub expires_at: Option<i64>,
    pub created_at: i64,
    pub active: bool,
}

impl TryFrom<Share> for ShareResponse {
    type Error = anyhow::Error;

    fn try_from(share: Share) -> Result<Self, Self::Error> {
        Ok(Self {
            id: share.id.map(|id| id.to_string()).unwrap_or_default(),
            target_user_id: share.target_user_id.to_string(),
            resource_type: share.resource_type,
            resource_id: share.resource_id.map(|id| id.to_string()),
            permissions: share
                .permissions
                .into_iter()
                .map(|p| p.to_string())
                .collect(),
            expires_at: share.expires_at.map(|dt| dt.timestamp_millis()),
            created_at: share.created_at.timestamp_millis(),
            active: share.active,
        })
    }
}

pub async fn create_share(
    State(state): State<AppState>,
    Extension(claims): Extension<Claims>,
    Json(req): Json<CreateShareRequest>,
) -> impl IntoResponse {
    if let Err(errors) = req.validate() {
        return (
            StatusCode::BAD_REQUEST,
            Json(serde_json::json!({
                "error": "validation failed",
                "details": errors.to_string()
            })),
        )
            .into_response();
    }

    // Find target user by email
    let target_user = match state.db.find_user_by_email(&req.target_user_email).await {
        Ok(Some(user)) => user,
        Ok(None) => {
            return (
                StatusCode::NOT_FOUND,
                Json(serde_json::json!({
                    "error": "target user not found"
                })),
            )
                .into_response();
        }
        Err(e) => {
            tracing::error!("Failed to find target user: {}", e);
            return (
                StatusCode::INTERNAL_SERVER_ERROR,
                Json(serde_json::json!({
                    "error": "database error"
                })),
            )
                .into_response();
        }
    };

    let target_user_id = match target_user.id {
        Some(id) => id,
        None => {
            return (
                StatusCode::INTERNAL_SERVER_ERROR,
                Json(serde_json::json!({
                    "error": "target user has no ID"
                })),
            )
                .into_response();
        }
    };

    let owner_id = match ObjectId::parse_str(&claims.sub) {
        Ok(id) => id,
        Err(_) => {
            return (
                StatusCode::BAD_REQUEST,
                Json(serde_json::json!({
                    "error": "invalid user ID format"
                })),
            )
                .into_response();
        }
    };

    // Parse resource_id if provided
    let resource_id = match req.resource_id {
        Some(id) => match ObjectId::parse_str(&id) {
            Ok(oid) => Some(oid),
            Err(_) => {
                return (
                    StatusCode::BAD_REQUEST,
                    Json(serde_json::json!({
                        "error": "invalid resource_id format"
                    })),
                )
                    .into_response();
            }
        },
        None => None,
    };

    // Parse permissions - support all permission types
    let permissions: Vec<Permission> = req
        .permissions
        .into_iter()
        .filter_map(|p| match p.to_lowercase().as_str() {
            "read" => Some(Permission::Read),
            "write" => Some(Permission::Write),
            "delete" => Some(Permission::Delete),
            "share" => Some(Permission::Share),
            "admin" => Some(Permission::Admin),
            _ => None,
        })
        .collect();

    if permissions.is_empty() {
        return (StatusCode::BAD_REQUEST, Json(serde_json::json!({
            "error": "at least one valid permission is required (read, write, delete, share, admin)"
        }))).into_response();
    }

    // Calculate expiration
    let expires_at = req.expires_days.map(|days| {
        mongodb::bson::DateTime::now().saturating_add_millis(days as i64 * 24 * 60 * 60 * 1000)
    });

    let share = Share::new(
        owner_id.clone(),
        target_user_id,
        req.resource_type,
        resource_id,
        permissions,
        expires_at,
    );

    match state.db.create_share(&share).await {
        Ok(_) => {
            let response: ShareResponse = match share.try_into() {
                Ok(r) => r,
                Err(_) => {
                    return (
                        StatusCode::INTERNAL_SERVER_ERROR,
                        Json(serde_json::json!({
                            "error": "failed to create share response"
                        })),
                    )
                        .into_response();
                }
            };
            (StatusCode::CREATED, Json(response)).into_response()
        }
        Err(e) => {
            tracing::error!("Failed to create share: {}", e);
            (
                StatusCode::INTERNAL_SERVER_ERROR,
                Json(serde_json::json!({
                    "error": "failed to create share"
                })),
            )
                .into_response()
        }
    }
}

pub async fn list_shares(
    State(state): State<AppState>,
    Extension(claims): Extension<Claims>,
) -> impl IntoResponse {
    let user_id = &claims.sub;

    match state.db.list_shares_for_user(user_id).await {
        Ok(shares) => {
            let responses: Vec<ShareResponse> = shares
                .into_iter()
                .filter_map(|s| ShareResponse::try_from(s).ok())
                .collect();
            (StatusCode::OK, Json(responses)).into_response()
        }
        Err(e) => {
            tracing::error!("Failed to list shares: {}", e);
            (
                StatusCode::INTERNAL_SERVER_ERROR,
                Json(serde_json::json!({
                    "error": "failed to list shares"
                })),
            )
                .into_response()
        }
    }
}

pub async fn get_share(State(state): State<AppState>, Path(id): Path<String>) -> impl IntoResponse {
    match state.db.get_share(&id).await {
        Ok(Some(share)) => {
            let response: ShareResponse = match share.try_into() {
                Ok(r) => r,
                Err(_) => {
                    return (
                        StatusCode::INTERNAL_SERVER_ERROR,
                        Json(serde_json::json!({
                            "error": "failed to create share response"
                        })),
                    )
                        .into_response();
                }
            };
            (StatusCode::OK, Json(response)).into_response()
        }
        Ok(None) => (
            StatusCode::NOT_FOUND,
            Json(serde_json::json!({
                "error": "share not found"
            })),
        )
            .into_response(),
        Err(e) => {
            tracing::error!("Failed to get share: {}", e);
            (
                StatusCode::INTERNAL_SERVER_ERROR,
                Json(serde_json::json!({
                    "error": "failed to get share"
                })),
            )
                .into_response()
        }
    }
}

#[derive(Debug, Deserialize, Validate)]
pub struct UpdateShareRequest {
    pub permissions: Option<Vec<String>>,
    #[serde(default)]
    pub active: Option<bool>,
    #[serde(default)]
    pub expires_days: Option<u64>,
}

pub async fn update_share(
    State(state): State<AppState>,
    Path(id): Path<String>,
    Extension(claims): Extension<Claims>,
    Json(req): Json<UpdateShareRequest>,
) -> impl IntoResponse {
    // First get the share
    let mut share = match state.db.get_share(&id).await {
        Ok(Some(s)) => s,
        Ok(None) => {
            return (
                StatusCode::NOT_FOUND,
                Json(serde_json::json!({
                    "error": "share not found"
                })),
            )
                .into_response();
        }
        Err(e) => {
            tracing::error!("Failed to get share: {}", e);
            return (
                StatusCode::INTERNAL_SERVER_ERROR,
                Json(serde_json::json!({
                    "error": "failed to get share"
                })),
            )
                .into_response();
        }
    };

    // Verify ownership
    let owner_id = match ObjectId::parse_str(&claims.sub) {
        Ok(id) => id,
        Err(_) => {
            return (
                StatusCode::BAD_REQUEST,
                Json(serde_json::json!({
                    "error": "invalid user ID format"
                })),
            )
                .into_response();
        }
    };

    if share.owner_id != owner_id {
        return (
            StatusCode::FORBIDDEN,
            Json(serde_json::json!({
                "error": "not authorized to modify this share"
            })),
        )
            .into_response();
    }

    // Update fields
    if let Some(permissions) = req.permissions {
        share.permissions = permissions
            .into_iter()
            .filter_map(|p| match p.to_lowercase().as_str() {
                "read" => Some(Permission::Read),
                "write" => Some(Permission::Write),
                "delete" => Some(Permission::Delete),
                "share" => Some(Permission::Share),
                "admin" => Some(Permission::Admin),
                _ => None,
            })
            .collect();
    }

    if let Some(active) = req.active {
        share.active = active;
    }

    if let Some(days) = req.expires_days {
        share.expires_at = Some(
            mongodb::bson::DateTime::now().saturating_add_millis(days as i64 * 24 * 60 * 60 * 1000),
        );
    }

    match state.db.update_share(&share).await {
        Ok(_) => {
            let response: ShareResponse = match share.try_into() {
                Ok(r) => r,
                Err(_) => {
                    return (
                        StatusCode::INTERNAL_SERVER_ERROR,
                        Json(serde_json::json!({
                            "error": "failed to create share response"
                        })),
                    )
                        .into_response();
                }
            };
            (StatusCode::OK, Json(response)).into_response()
        }
        Err(e) => {
            tracing::error!("Failed to update share: {}", e);
            (
                StatusCode::INTERNAL_SERVER_ERROR,
                Json(serde_json::json!({
                    "error": "failed to update share"
                })),
            )
                .into_response()
        }
    }
}

pub async fn delete_share(
    State(state): State<AppState>,
    Path(id): Path<String>,
    Extension(claims): Extension<Claims>,
) -> impl IntoResponse {
    // First get the share to verify ownership
    let share = match state.db.get_share(&id).await {
        Ok(Some(s)) => s,
        Ok(None) => {
            return (
                StatusCode::NOT_FOUND,
                Json(serde_json::json!({
                    "error": "share not found"
                })),
            )
                .into_response()
        }
        Err(e) => {
            tracing::error!("Failed to get share: {}", e);
            return (
                StatusCode::INTERNAL_SERVER_ERROR,
                Json(serde_json::json!({
                    "error": "failed to get share"
                })),
            )
                .into_response();
        }
    };

    // Verify ownership
    let owner_id = match ObjectId::parse_str(&claims.sub) {
        Ok(id) => id,
        Err(_) => {
            return (
                StatusCode::BAD_REQUEST,
                Json(serde_json::json!({
                    "error": "invalid user ID format"
                })),
            )
                .into_response();
        }
    };

    if share.owner_id != owner_id {
        return (
            StatusCode::FORBIDDEN,
            Json(serde_json::json!({
                "error": "not authorized to delete this share"
            })),
        )
            .into_response();
    }

    match state.db.delete_share(&id).await {
        Ok(_) => (StatusCode::NO_CONTENT, ()).into_response(),
        Err(e) => {
            tracing::error!("Failed to delete share: {}", e);
            (
                StatusCode::INTERNAL_SERVER_ERROR,
                Json(serde_json::json!({
                    "error": "failed to delete share"
                })),
            )
                .into_response()
        }
    }
}
