use rusqlite::Connection;
use serde::{Serialize, Deserialize};

use crate::crypto::encryption::{encrypt_data_with_user_key, decrypt_data_with_user_key, hash_element};
use crate::crypto::key_manager::get_user_encryption_key;
use crate::domains::act::service::ActChapter;
use crate::domains::incident::repo;
use crate::domains::tombstone::repo as tombstone_repo;
use crate::error::AppResult;
use crate::helpers::{create_unique_id, timestamp_in_seconds};
use crate::shared::types::Lang;

#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct IncidentProps {
    pub incident_id: String,
    pub title: String,
    pub summary: String,
    pub chapters: Option<Vec<ActChapter>>,
}

/// Creates a new incident for a book.
/// Encrypts the incident name and generates a hashed version for indexing.
/// * `conn` - Database connection
/// * `user_id` - The unique identifier of the user creating the incident
/// * `book_id` - The unique identifier of the book to add the incident to
/// * `name` - The plain text name of the incident
/// * `lang` - The language for error messages
/// * `existing_incident_id` - Optional existing incident ID to use instead of generating a new one
/// Returns the unique identifier of the created incident.
pub fn add_new_incident(
    conn: &Connection, user_id: &str, book_id: &str, name: &str,
    lang: Lang, existing_incident_id: Option<&str>,
) -> AppResult<String> {
    let user_key: String = get_user_encryption_key(user_id)?;
    let encrypted_name: String = encrypt_data_with_user_key(name, &user_key)?;
    let hashed_name: String = hash_element(name);
    let incident_id: String = create_unique_id(existing_incident_id);
    let last_update: i64 = timestamp_in_seconds();
    repo::insert_new_incident(conn, &incident_id, user_id, book_id, &encrypted_name, &hashed_name, last_update, lang)
}

/// Retrieves all incidents for a specific book with their associated chapters.
/// Decrypts incident titles and summaries using the user's encryption key.
/// * `conn` - Database connection
/// * `user_id` - The unique identifier of the user
/// * `book_id` - The unique identifier of the book
/// * `act_chapters` - Array of chapters from acts to associate with incidents
/// * `lang` - The language for error messages
/// Returns an array of incident properties with decrypted data.
pub fn get_incitents_incidents(
    conn: &Connection, user_id: &str, book_id: &str,
    act_chapters: &[ActChapter], lang: Lang,
) -> AppResult<Vec<IncidentProps>> {
    let incident_query_results: Vec<repo::IncidentQuery> = repo::fetch_all_incitent_incidents(conn, user_id, book_id, lang)?;
    let user_key: String = get_user_encryption_key(user_id)?;
    let mut incidents: Vec<IncidentProps> = Vec::new();

    if !incident_query_results.is_empty() {
        for incident_record in &incident_query_results {
            let mut associated_chapters: Vec<ActChapter> = Vec::new();
            for chapter in act_chapters {
                if let Some(ref incident_id) = chapter.incident_id {
                    if incident_id == &incident_record.incident_id {
                        associated_chapters.push(ActChapter {
                            chapter_info_id: chapter.chapter_info_id,
                            chapter_id: chapter.chapter_id.clone(),
                            title: chapter.title.clone(),
                            chapter_order: chapter.chapter_order,
                            act_id: chapter.act_id,
                            incident_id: chapter.incident_id.clone(),
                            plot_point_id: chapter.plot_point_id.clone(),
                            summary: chapter.summary.clone(),
                            goal: chapter.goal.clone(),
                        });
                    }
                }
            }
            let decrypted_title: String = if incident_record.title.is_empty() { String::new() } else { decrypt_data_with_user_key(&incident_record.title, &user_key)? };
            let decrypted_summary: String = if incident_record.summary.is_empty() { String::new() } else { decrypt_data_with_user_key(&incident_record.summary, &user_key)? };
            incidents.push(IncidentProps {
                incident_id: incident_record.incident_id.clone(),
                title: decrypted_title,
                summary: decrypted_summary,
                chapters: Some(associated_chapters),
            });
        }
    }

    Ok(incidents)
}

/// Removes an incident from a book.
/// * `conn` - Database connection
/// * `user_id` - The unique identifier of the user
/// * `book_id` - The unique identifier of the book
/// * `incident_id` - The unique identifier of the incident to remove
/// * `deleted_at` - The timestamp of deletion
/// * `lang` - The language for error messages
/// Returns true if the incident was successfully deleted, false otherwise.
pub fn remove_incident(
    conn: &Connection, user_id: &str, book_id: &str, incident_id: &str,
    deleted_at: i64, lang: Lang,
) -> AppResult<bool> {
    let deleted: bool = repo::delete_incident(conn, user_id, book_id, incident_id, lang)?;
    if deleted {
        tombstone_repo::insert(conn, incident_id, "book_incidents", incident_id, Some(book_id), user_id, deleted_at, lang)?;
    }
    Ok(deleted)
}
