use crate::error::RariError;
use smallvec::SmallVec;

pub type DependencyList = SmallVec<[String; 4]>;

fn compile_regex(pattern: &str, context: &str) -> Result<regex::Regex, RariError> {
    regex::Regex::new(pattern)
        .map_err(|_| RariError::js_execution(format!("Failed to compile {context} regex")))
}

pub fn extract_dependencies(code: &str) -> DependencyList {
    let import_regex = match compile_regex(
        r#"(?:import|from)\s*((?:['"])(.*?)(?:['"]))"#,
        "dependency extraction",
    ) {
        Ok(regex) => regex,
        Err(_) => return SmallVec::new(),
    };
    let mut dependencies = SmallVec::new();

    for captures in import_regex.captures_iter(code) {
        if captures.len() >= 3
            && let Some(import_path) = captures.get(2)
        {
            let import_path_str = import_path.as_str().to_string();
            if !import_path_str.starts_with("react")
                && (import_path_str.starts_with(".")
                    || import_path_str.starts_with("/")
                    || import_path_str.contains("/"))
            {
                dependencies.push(import_path_str);
            }
        }
    }

    dependencies
}

pub fn hash_string(s: &str) -> String {
    use std::collections::hash_map::DefaultHasher;
    use std::hash::{Hash, Hasher};

    let mut hasher = DefaultHasher::new();
    s.hash(&mut hasher);
    format!("{:x}", hasher.finish())
}

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

    #[test]
    fn test_extract_dependencies() {
        let code = r#"
        import React from 'react';
        import { useState } from 'react';
        import Button from './Button';
        import { Card, CardContent } from '../components/Card';

        export default function Component() {
            return <div>Test</div>;
        }
        "#;

        let dependencies = extract_dependencies(code);
        assert_eq!(dependencies.len(), 2);
        assert!(dependencies.contains(&"./Button".to_string()));
        assert!(dependencies.contains(&"../components/Card".to_string()));
    }
}
