pub mod router;
pub mod zhihu;
pub mod zhihu_hotlist;
pub mod zhihu_hotlist_store;
pub mod zhihu_navigation;

use std::path::PathBuf;

use crate::pipe::{BrowserPipeTool, PipeError, Transport};

fn relative_skill_resource_path(resource_name: &str) -> PathBuf {
    PathBuf::from("resources")
        .join("skills")
        .join(resource_name)
}

pub(crate) fn skill_resource_path_from_executable(
    executable_path: PathBuf,
    resource_name: &str,
) -> PathBuf {
    executable_path
        .parent()
        .map(|dir| dir.join("resources").join("skills").join(resource_name))
        .unwrap_or_else(|| relative_skill_resource_path(resource_name))
}

pub(crate) fn default_skill_resource_path(resource_name: &str) -> PathBuf {
    std::env::current_exe()
        .ok()
        .map(|path| skill_resource_path_from_executable(path, resource_name))
        .filter(|path| path.exists())
        .unwrap_or_else(|| relative_skill_resource_path(resource_name))
}

pub fn try_execute_skill<T: Transport>(
    transport: &T,
    browser_tool: &BrowserPipeTool<T>,
    instruction: &str,
) -> Result<Option<String>, PipeError> {
    match router::route_instruction(instruction)
        .map_err(|err| PipeError::Protocol(err.to_string()))?
    {
        Some(router::RoutedSkill::ZhihuWrite(req)) => {
            let result = zhihu::execute(transport, browser_tool, req)
                .map_err(|err| PipeError::Protocol(err.to_string()))?;
            Ok(Some(result.summary))
        }
        Some(router::RoutedSkill::ZhihuHotlistCollect(req)) => {
            let result = zhihu_hotlist::execute_collect(transport, browser_tool, req)
                .map_err(|err| PipeError::Protocol(err.to_string()))?;
            Ok(Some(result.summary))
        }
        Some(router::RoutedSkill::ZhihuHotlistReport(req)) => {
            let result = zhihu_hotlist::execute_report(req)
                .map_err(|err| PipeError::Protocol(err.to_string()))?;
            Ok(Some(result.summary))
        }
        Some(router::RoutedSkill::ZhihuNavigate(req)) => {
            let result = zhihu_navigation::execute(transport, browser_tool, req)
                .map_err(|err| PipeError::Protocol(err.to_string()))?;
            Ok(Some(result.summary))
        }
        None => Ok(None),
    }
}

#[cfg(test)]
mod tests {
    use std::path::PathBuf;

    use super::skill_resource_path_from_executable;

    #[test]
    fn skill_resource_path_uses_executable_directory_instead_of_cwd() {
        let executable_path = PathBuf::from("/tmp/out/KylinRelease/sgclaw");

        let resolved =
            skill_resource_path_from_executable(executable_path, "zhihu_navigation_pages.json");

        assert_eq!(
            resolved,
            PathBuf::from("/tmp/out/KylinRelease/resources/skills/zhihu_navigation_pages.json")
        );
    }
}
