use thiserror::Error;

use super::zhihu::ZhihuWriteRequest;
use super::zhihu_hotlist::{ZhihuHotlistCollectRequest, ZhihuHotlistReportRequest};
use super::zhihu_navigation::{
    try_route_alias as try_route_zhihu_navigation_alias, ZhihuNavigateRequest,
};

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum RoutedSkill {
    ZhihuWrite(ZhihuWriteRequest),
    ZhihuHotlistCollect(ZhihuHotlistCollectRequest),
    ZhihuHotlistReport(ZhihuHotlistReportRequest),
    ZhihuNavigate(ZhihuNavigateRequest),
}

#[derive(Debug, Error)]
pub enum RouterError {
    #[error("missing skill name after skill: prefix")]
    MissingSkillName,
    #[error("missing JSON arguments for skill: {0}")]
    MissingArguments(String),
    #[error("unknown skill: {0}")]
    UnknownSkill(String),
    #[error("invalid JSON arguments for skill {skill}: {message}")]
    InvalidArguments { skill: String, message: String },
}

pub fn route_instruction(instruction: &str) -> Result<Option<RoutedSkill>, RouterError> {
    let trimmed = instruction.trim();
    if trimmed.starts_with("skill:") {
        return parse_explicit_skill(trimmed).map(Some);
    }

    match try_route_zhihu_navigation_alias(trimmed) {
        Ok(Some(req)) => Ok(Some(RoutedSkill::ZhihuNavigate(req))),
        Ok(None) => Ok(None),
        Err(err) => Err(RouterError::InvalidArguments {
            skill: "zhihu_navigate".to_string(),
            message: err.to_string(),
        }),
    }
}

fn parse_explicit_skill(instruction: &str) -> Result<RoutedSkill, RouterError> {
    let rest = instruction
        .strip_prefix("skill:")
        .ok_or(RouterError::MissingSkillName)?
        .trim();

    if rest.is_empty() {
        return Err(RouterError::MissingSkillName);
    }

    let split_at = rest
        .find(char::is_whitespace)
        .ok_or_else(|| RouterError::MissingArguments(rest.to_string()))?;
    let name = rest[..split_at].trim();
    let args = rest[split_at..].trim();

    if args.is_empty() {
        return Err(RouterError::MissingArguments(name.to_string()));
    }

    match name {
        "zhihu_write" => serde_json::from_str::<ZhihuWriteRequest>(args)
            .map(RoutedSkill::ZhihuWrite)
            .map_err(|err| RouterError::InvalidArguments {
                skill: name.to_string(),
                message: err.to_string(),
            }),
        "zhihu_hotlist_collect" => serde_json::from_str::<ZhihuHotlistCollectRequest>(args)
            .map(RoutedSkill::ZhihuHotlistCollect)
            .map_err(|err| RouterError::InvalidArguments {
                skill: name.to_string(),
                message: err.to_string(),
            }),
        "zhihu_hotlist_report" => serde_json::from_str::<ZhihuHotlistReportRequest>(args)
            .map(RoutedSkill::ZhihuHotlistReport)
            .map_err(|err| RouterError::InvalidArguments {
                skill: name.to_string(),
                message: err.to_string(),
            }),
        "zhihu_navigate" => serde_json::from_str::<ZhihuNavigateRequest>(args)
            .map(RoutedSkill::ZhihuNavigate)
            .map_err(|err| RouterError::InvalidArguments {
                skill: name.to_string(),
                message: err.to_string(),
            }),
        other => Err(RouterError::UnknownSkill(other.to_string())),
    }
}
