use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use tauri::AppHandle;
use tauri_plugin_store::StoreExt;

const SNIPPETS_STORE_KEY: &str = "snippets";

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Snippet {
    pub id: String,
    pub name: String,
    pub content: String,
    pub category: String,
    pub is_default: bool,
    pub created_at: DateTime<Utc>,
    pub updated_at: DateTime<Utc>,
}

fn get_default_snippets() -> Vec<Snippet> {
    let now = Utc::now();
    vec![
        Snippet {
            id: "default-explain-code".to_string(),
            name: "Explain this code".to_string(),
            content: "Please explain what this code does, step by step:".to_string(),
            category: "Code Review".to_string(),
            is_default: true,
            created_at: now,
            updated_at: now,
        },
        Snippet {
            id: "default-fix-error".to_string(),
            name: "Fix this error".to_string(),
            content: "I'm getting the following error. Can you help me fix it?".to_string(),
            category: "Debugging".to_string(),
            is_default: true,
            created_at: now,
            updated_at: now,
        },
        Snippet {
            id: "default-write-tests".to_string(),
            name: "Write tests".to_string(),
            content: "Please write unit tests for this code with good coverage:".to_string(),
            category: "Testing".to_string(),
            is_default: true,
            created_at: now,
            updated_at: now,
        },
        Snippet {
            id: "default-refactor".to_string(),
            name: "Refactor for clarity".to_string(),
            content: "Please refactor this code to improve readability and maintainability:".to_string(),
            category: "Code Review".to_string(),
            is_default: true,
            created_at: now,
            updated_at: now,
        },
        Snippet {
            id: "default-optimize".to_string(),
            name: "Optimize performance".to_string(),
            content: "Please analyze this code for performance issues and suggest optimizations:".to_string(),
            category: "Performance".to_string(),
            is_default: true,
            created_at: now,
            updated_at: now,
        },
        Snippet {
            id: "default-review-pr".to_string(),
            name: "Review PR".to_string(),
            content: "Please review this pull request and provide feedback on code quality, potential issues, and suggestions for improvement.".to_string(),
            category: "Code Review".to_string(),
            is_default: true,
            created_at: now,
            updated_at: now,
        },
        Snippet {
            id: "default-add-comments".to_string(),
            name: "Add documentation".to_string(),
            content: "Please add clear documentation comments to this code explaining what it does:".to_string(),
            category: "Documentation".to_string(),
            is_default: true,
            created_at: now,
            updated_at: now,
        },
        Snippet {
            id: "default-security-review".to_string(),
            name: "Security review".to_string(),
            content: "Please review this code for security vulnerabilities and suggest fixes:".to_string(),
            category: "Security".to_string(),
            is_default: true,
            created_at: now,
            updated_at: now,
        },
    ]
}

fn load_all_snippets(app: &AppHandle) -> Result<Vec<Snippet>, String> {
    let store = app
        .store("hikari-snippets.json")
        .map_err(|e| e.to_string())?;

    match store.get(SNIPPETS_STORE_KEY) {
        Some(value) => {
            let mut snippets: Vec<Snippet> =
                serde_json::from_value(value.clone()).map_err(|e| e.to_string())?;

            // Ensure default snippets exist (in case new ones were added in an update)
            let defaults = get_default_snippets();
            for default in defaults {
                if !snippets.iter().any(|s| s.id == default.id) {
                    snippets.push(default);
                }
            }

            Ok(snippets)
        }
        None => Ok(get_default_snippets()),
    }
}

fn save_all_snippets(app: &AppHandle, snippets: &[Snippet]) -> Result<(), String> {
    let store = app
        .store("hikari-snippets.json")
        .map_err(|e| e.to_string())?;

    let value = serde_json::to_value(snippets).map_err(|e| e.to_string())?;
    store.set(SNIPPETS_STORE_KEY, value);
    store.save().map_err(|e| e.to_string())?;

    Ok(())
}

#[tauri::command]
pub async fn list_snippets(app: AppHandle) -> Result<Vec<Snippet>, String> {
    let mut snippets = load_all_snippets(&app)?;

    // Sort by category, then by name
    snippets.sort_by(|a, b| {
        let cat_cmp = a.category.cmp(&b.category);
        if cat_cmp == std::cmp::Ordering::Equal {
            a.name.cmp(&b.name)
        } else {
            cat_cmp
        }
    });

    Ok(snippets)
}

#[tauri::command]
pub async fn save_snippet(app: AppHandle, snippet: Snippet) -> Result<(), String> {
    let mut snippets = load_all_snippets(&app)?;

    // Update existing or add new
    if let Some(existing) = snippets.iter_mut().find(|s| s.id == snippet.id) {
        // Don't allow editing default snippets' is_default flag
        let mut updated = snippet;
        updated.is_default = existing.is_default;
        *existing = updated;
    } else {
        snippets.push(snippet);
    }

    save_all_snippets(&app, &snippets)
}

#[tauri::command]
pub async fn delete_snippet(app: AppHandle, snippet_id: String) -> Result<(), String> {
    let mut snippets = load_all_snippets(&app)?;

    // Don't allow deleting default snippets
    if snippets
        .iter()
        .any(|s| s.id == snippet_id && s.is_default)
    {
        return Err("Cannot delete default snippets".to_string());
    }

    snippets.retain(|s| s.id != snippet_id);
    save_all_snippets(&app, &snippets)
}

#[tauri::command]
pub async fn get_snippet_categories(app: AppHandle) -> Result<Vec<String>, String> {
    let snippets = load_all_snippets(&app)?;
    let mut categories: Vec<String> = snippets.iter().map(|s| s.category.clone()).collect();
    categories.sort();
    categories.dedup();
    Ok(categories)
}

#[tauri::command]
pub async fn reset_default_snippets(app: AppHandle) -> Result<(), String> {
    let mut snippets = load_all_snippets(&app)?;

    // Remove all default snippets
    snippets.retain(|s| !s.is_default);

    // Add fresh default snippets
    snippets.extend(get_default_snippets());

    save_all_snippets(&app, &snippets)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_default_snippets_exist() {
        let defaults = get_default_snippets();
        assert!(!defaults.is_empty());
        assert!(defaults.iter().all(|s| s.is_default));
    }

    #[test]
    fn test_default_snippets_have_required_fields() {
        let defaults = get_default_snippets();
        for snippet in defaults {
            assert!(!snippet.id.is_empty());
            assert!(!snippet.name.is_empty());
            assert!(!snippet.content.is_empty());
            assert!(!snippet.category.is_empty());
        }
    }
}
