use std::{collections::HashMap, sync::Mutex};

use anyhow::{anyhow, Result};

use crate::models::{SubtitleSegment, SubtitleTask};

#[derive(Default)]
pub struct AppState {
    tasks: Mutex<HashMap<String, SubtitleTask>>,
}

impl AppState {
    pub fn upsert_task(&self, task: SubtitleTask) -> Result<()> {
        let mut guard = self.tasks.lock().map_err(|_| anyhow!("task store poisoned"))?;
        guard.insert(task.id.clone(), task);
        Ok(())
    }

    pub fn get_task(&self, task_id: &str) -> Result<SubtitleTask> {
        let guard = self.tasks.lock().map_err(|_| anyhow!("task store poisoned"))?;
        guard
            .get(task_id)
            .cloned()
            .ok_or_else(|| anyhow!("task not found: {task_id}"))
    }

    pub fn list_tasks(&self) -> Result<Vec<SubtitleTask>> {
        let guard = self.tasks.lock().map_err(|_| anyhow!("task store poisoned"))?;
        let mut tasks = guard.values().cloned().collect::<Vec<_>>();
        tasks.sort_by(|left, right| right.id.cmp(&left.id));
        Ok(tasks)
    }

    pub fn update_segment(&self, segment: SubtitleSegment) -> Result<SubtitleTask> {
        let mut guard = self.tasks.lock().map_err(|_| anyhow!("task store poisoned"))?;
        let task = guard
            .get_mut(&segment.task_id)
            .ok_or_else(|| anyhow!("task not found: {}", segment.task_id))?;

        match task.segments.iter_mut().find(|item| item.id == segment.id) {
            Some(existing) => *existing = segment,
            None => task.segments.push(segment),
        }

        Ok(task.clone())
    }
}
