use std::path::PathBuf;
use std::sync::{Arc, Mutex};
use super::{RaidLevel, MemberStatus, RaidAlgorithm, RaidError};

#[derive(Debug, Clone)]
pub struct RaidMember {
    pub device_id: String,
    pub device_path: PathBuf,
    pub size: u64,
    pub status: MemberStatus,
}

#[derive(Debug)]
pub struct RaidArray {
    pub raid_level: RaidLevel,
    pub members: Vec<RaidMember>,
    pub stripe_size: u64,
    pub total_size: u64,
}

pub struct RaidController {
    arrays: Mutex<Vec<Arc<RaidArray>>>,
}

impl RaidController {
    pub fn new() -> Self {
        RaidController {
            arrays: Mutex::new(Vec::new()),
        }
    }
    
    pub fn create_array(
        &self,
        level: RaidLevel,
        member_paths: Vec<PathBuf>,
        stripe_size: u64,
    ) -> Result<String, RaidError> {
        let members: Vec<RaidMember> = member_paths
            .iter()
            .enumerate()
            .map(|(i, path)| {
                let size = if path.exists() {
                    std::fs::metadata(path).unwrap().len()
                } else {
                    0
                };
                RaidMember {
                    device_id: format!("member_{}", i),
                    device_path: path.clone(),
                    size,
                    status: MemberStatus::Online,
                }
            })
            .collect();
        
        let total_size = calculate_total_size(level, &members, stripe_size);
        
        let array = RaidArray {
            raid_level: level,
            members,
            stripe_size,
            total_size,
        };
        
        let array_id = format!("raid_{}", chrono::Utc::now().timestamp());
        let mut arrays = self.arrays.lock().unwrap();
        arrays.push(Arc::new(array));
        
        Ok(array_id)
    }
    
    pub fn get_array(&self, _array_id: &str) -> Option<Arc<RaidArray>> {
        let arrays = self.arrays.lock().unwrap();
        arrays.iter().find(|_a| true).cloned()
    }
    
    pub fn read(&self, array_id: &str, offset: u64, size: u64) -> Result<Vec<u8>, RaidError> {
        let array = self.get_array(array_id)
            .ok_or("RAID array not found")?;
        
        match array.raid_level {
            RaidLevel::RAID0 => {
                let mut raid0 = super::level_0::Raid0::new(array.clone());
                raid0.read(offset, size)
            },
            RaidLevel::RAID1 => {
                let mut raid1 = super::level_1::Raid1::new(array.clone());
                raid1.read(offset, size)
            },
            RaidLevel::RAID5 => {
                let mut raid5 = super::level_5::Raid5::new(array.clone())?;
                raid5.read(offset, size)
            },
            _ => Err("RAID level not implemented yet".into()),
        }
    }
    
    pub fn write(&self, array_id: &str, offset: u64, data: &[u8]) -> Result<(), RaidError> {
        let array = self.get_array(array_id)
            .ok_or("RAID array not found")?;
        
        match array.raid_level {
            RaidLevel::RAID0 => {
                let mut raid0 = super::level_0::Raid0::new(array.clone());
                raid0.write(offset, data)
            },
            RaidLevel::RAID1 => {
                let mut raid1 = super::level_1::Raid1::new(array.clone());
                raid1.write(offset, data)
            },
            RaidLevel::RAID5 => {
                let mut raid5 = super::level_5::Raid5::new(array.clone())?;
                raid5.write(offset, data)
            },
            _ => Err("RAID level not implemented yet".into()),
        }
    }
}

fn calculate_total_size(level: RaidLevel, members: &[RaidMember], _stripe_size: u64) -> u64 {
    match level {
        RaidLevel::RAID0 => {
            members.iter().map(|m| m.size).sum()
        },
        RaidLevel::RAID1 => {
            members.iter().map(|m| m.size).min().unwrap_or(0)
        },
        RaidLevel::RAID5 => {
            let min_size = members.iter().map(|m| m.size).min().unwrap_or(0);
            min_size * (members.len() - 1) as u64
        },
        _ => 0,
    }
}