use loco_rs::prelude::*;
use sea_orm::{QueryOrder, QuerySelect, PaginatorTrait};
use serde::{Deserialize, Serialize};

pub use super::_entities::books::{self, ActiveModel, Entity, Model};

#[derive(Debug, Deserialize, Serialize)]
pub struct CreateBookParams {
    pub title: String,
    pub author: String,
    pub description: Option<String>,
    pub cover: Option<String>,
    pub content: String,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct PaginatedBooks {
    pub books: Vec<Model>,
    pub total: u64,
    pub page: i32,
    pub per_page: i32,
    pub total_pages: i32,
}

impl Model {
    /// Find all books with pagination
    pub async fn list_paginated(
        db: &DatabaseConnection,
        page: i32,
        per_page: i32,
    ) -> ModelResult<PaginatedBooks> {
        let total = books::Entity::find().count(db).await?;
        let total_pages = ((total as f64) / (per_page as f64)).ceil() as i32;
        
        let books = books::Entity::find()
            .order_by_desc(books::Column::Id)
            .limit(per_page as u64)
            .offset(((page - 1) * per_page) as u64)
            .all(db)
            .await?;
        
        Ok(PaginatedBooks {
            books,
            total,
            page,
            per_page,
            total_pages,
        })
    }

    /// Find all books (legacy, for backward compatibility)
    pub async fn list(db: &DatabaseConnection) -> ModelResult<Vec<Model>> {
        let books = books::Entity::find()
            .order_by_desc(books::Column::Id)
            .all(db)
            .await?;
        Ok(books)
    }

    /// Find a book by ID
    pub async fn find_by_id(db: &DatabaseConnection, id: i32) -> ModelResult<Self> {
        let book = books::Entity::find_by_id(id).one(db).await?;
        book.ok_or_else(|| ModelError::EntityNotFound)
    }

    /// Create a new book
    pub async fn create(db: &DatabaseConnection, params: &CreateBookParams) -> ModelResult<Self> {
        let book = books::ActiveModel {
            title: ActiveValue::Set(params.title.clone()),
            author: ActiveValue::Set(params.author.clone()),
            description: ActiveValue::Set(params.description.clone()),
            cover: ActiveValue::Set(params.cover.clone()),
            content: ActiveValue::Set(params.content.clone()),
            ..Default::default()
        };
        let book = book.insert(db).await?;
        Ok(book)
    }

    /// Update a book
    pub async fn update(&self, db: &DatabaseConnection, params: &CreateBookParams) -> ModelResult<Self> {
        let mut book: books::ActiveModel = self.clone().into();
        book.title = ActiveValue::Set(params.title.clone());
        book.author = ActiveValue::Set(params.author.clone());
        book.description = ActiveValue::Set(params.description.clone());
        book.cover = ActiveValue::Set(params.cover.clone());
        book.content = ActiveValue::Set(params.content.clone());
        let book = book.update(db).await?;
        Ok(book)
    }

    /// Delete a book
    pub async fn delete(&self, db: &DatabaseConnection) -> ModelResult<()> {
        let book: books::ActiveModel = self.clone().into();
        book.delete(db).await?;
        Ok(())
    }
}
