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

const DRAFTS_STORE_FILE: &str = "hikari-drafts.json";
const DRAFTS_STORE_KEY: &str = "drafts";

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Draft {
    pub id: String,
    pub content: String,
    pub saved_at: String,
}

fn load_all_drafts(app: &AppHandle) -> Result<Vec<Draft>, String> {
    let store = app
        .store(DRAFTS_STORE_FILE)
        .map_err(|e| e.to_string())?;

    match store.get(DRAFTS_STORE_KEY) {
        Some(value) => serde_json::from_value(value.clone()).map_err(|e| e.to_string()),
        None => Ok(vec![]),
    }
}

fn save_all_drafts(app: &AppHandle, drafts: &[Draft]) -> Result<(), String> {
    let store = app
        .store(DRAFTS_STORE_FILE)
        .map_err(|e| e.to_string())?;

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

    Ok(())
}

#[tauri::command]
pub async fn list_drafts(app: AppHandle) -> Result<Vec<Draft>, String> {
    let mut drafts = load_all_drafts(&app)?;
    // Sort newest first — ISO 8601 timestamps sort lexicographically
    drafts.sort_by(|a, b| b.saved_at.cmp(&a.saved_at));
    Ok(drafts)
}

#[tauri::command]
pub async fn save_draft(app: AppHandle, content: String) -> Result<Draft, String> {
    let mut drafts = load_all_drafts(&app)?;

    let draft = Draft {
        id: Uuid::new_v4().to_string(),
        content,
        saved_at: Utc::now().to_rfc3339(),
    };

    drafts.push(draft.clone());
    save_all_drafts(&app, &drafts)?;

    Ok(draft)
}

#[tauri::command]
pub async fn delete_draft(app: AppHandle, draft_id: String) -> Result<(), String> {
    let mut drafts = load_all_drafts(&app)?;
    drafts.retain(|d| d.id != draft_id);
    save_all_drafts(&app, &drafts)
}

#[tauri::command]
pub async fn delete_all_drafts(app: AppHandle) -> Result<(), String> {
    save_all_drafts(&app, &[])
}

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

    fn make_draft(id: &str, content: &str, saved_at: &str) -> Draft {
        Draft {
            id: id.to_string(),
            content: content.to_string(),
            saved_at: saved_at.to_string(),
        }
    }

    #[test]
    fn test_draft_serialization() {
        let draft = make_draft("test-id", "Hello world", "2026-01-01T00:00:00+00:00");
        let json = serde_json::to_string(&draft).expect("Failed to serialize");
        let parsed: Draft = serde_json::from_str(&json).expect("Failed to deserialize");

        assert_eq!(parsed.id, draft.id);
        assert_eq!(parsed.content, draft.content);
        assert_eq!(parsed.saved_at, draft.saved_at);
    }

    #[test]
    fn test_draft_clone() {
        let original = make_draft("clone-id", "Clone me", "2026-01-01T00:00:00+00:00");
        let cloned = original.clone();

        assert_eq!(original.id, cloned.id);
        assert_eq!(original.content, cloned.content);
        assert_eq!(original.saved_at, cloned.saved_at);
    }

    #[test]
    fn test_sort_newest_first() {
        let mut drafts = [
            make_draft("a", "First", "2026-01-01T00:00:00+00:00"),
            make_draft("b", "Third", "2026-01-03T00:00:00+00:00"),
            make_draft("c", "Second", "2026-01-02T00:00:00+00:00"),
        ];

        drafts.sort_by(|a, b| b.saved_at.cmp(&a.saved_at));

        assert_eq!(drafts[0].id, "b");
        assert_eq!(drafts[1].id, "c");
        assert_eq!(drafts[2].id, "a");
    }

    #[test]
    fn test_retain_excludes_deleted() {
        let mut drafts = vec![
            make_draft("keep-1", "Keep me", "2026-01-01T00:00:00+00:00"),
            make_draft("delete-me", "Delete me", "2026-01-02T00:00:00+00:00"),
            make_draft("keep-2", "Keep me too", "2026-01-03T00:00:00+00:00"),
        ];

        let target_id = "delete-me".to_string();
        drafts.retain(|d| d.id != target_id);

        assert_eq!(drafts.len(), 2);
        assert!(drafts.iter().all(|d| d.id != "delete-me"));
    }

    #[test]
    fn test_find_by_id() {
        let drafts = [
            make_draft("draft-1", "First draft", "2026-01-01T00:00:00+00:00"),
            make_draft("draft-2", "Second draft", "2026-01-02T00:00:00+00:00"),
            make_draft("draft-3", "Third draft", "2026-01-03T00:00:00+00:00"),
        ];

        let found = drafts.iter().find(|d| d.id == "draft-2");
        assert!(found.is_some());
        assert_eq!(found.unwrap().content, "Second draft");

        let not_found = drafts.iter().find(|d| d.id == "draft-999");
        assert!(not_found.is_none());
    }

    #[test]
    fn test_multiline_content() {
        let content = "Line 1\nLine 2\nLine 3";
        let draft = make_draft("multi", content, "2026-01-01T00:00:00+00:00");

        assert!(draft.content.contains('\n'));
        assert_eq!(draft.content.split('\n').count(), 3);
    }

    #[test]
    fn test_empty_after_delete_all() {
        let mut drafts = vec![
            make_draft("a", "A", "2026-01-01T00:00:00+00:00"),
            make_draft("b", "B", "2026-01-02T00:00:00+00:00"),
        ];

        drafts.clear();

        assert!(drafts.is_empty());
    }

    #[test]
    fn test_uuid_format() {
        // UUIDs should be non-empty and contain hyphens
        let id = Uuid::new_v4().to_string();
        assert!(!id.is_empty());
        assert!(id.contains('-'));
        assert_eq!(id.len(), 36);
    }

    #[test]
    fn test_timestamp_is_rfc3339() {
        let ts = Utc::now().to_rfc3339();
        // RFC 3339 timestamps contain T and + or Z
        assert!(ts.contains('T'));
        assert!(ts.ends_with("+00:00") || ts.ends_with('Z'));
    }
}
