use std::sync::Arc;
use super::controller::RaidArray;
use super::{RaidAlgorithm, RaidLevel, RaidError, MemberStatus};

pub struct Raid0 {
    array: Arc<RaidArray>,
}

impl Raid0 {
    pub fn new(array: Arc<RaidArray>) -> Self {
        Raid0 { array }
    }
    
    fn locate_block(&self, block_offset: u64) -> (usize, u64) {
        let stripe_index = block_offset / self.array.stripe_size;
        let member_index = stripe_index % self.array.members.len() as u64;
        let member_offset = (stripe_index / self.array.members.len() as u64) * self.array.stripe_size;
        
        (member_index as usize, member_offset)
    }
}

impl RaidAlgorithm for Raid0 {
    fn read(&mut self, block_offset: u64, size: u64) -> Result<Vec<u8>, RaidError> {
        let mut result = Vec::with_capacity(size as usize);
        let mut current_offset = block_offset;
        
        while result.len() < size as usize {
            let (member_index, member_offset) = self.locate_block(current_offset);
            let member = &self.array.members[member_index];
            
            if member.status != MemberStatus::Online {
                return Err("Member offline".into());
            }
            
            let chunk_size = std::cmp::min(
                self.array.stripe_size,
                size - result.len() as u64
            );
            
            let file = std::fs::File::open(&member.device_path)?;
            use std::io::{Read, Seek};
            let mut file = file;
            file.seek(std::io::SeekFrom::Start(member_offset + current_offset % self.array.stripe_size))?;
            
            let mut chunk = vec![0u8; chunk_size as usize];
            file.read_exact(&mut chunk)?;
            result.extend_from_slice(&chunk);
            
            current_offset += chunk_size;
        }
        
        Ok(result)
    }
    
    fn write(&mut self, block_offset: u64, data: &[u8]) -> Result<(), RaidError> {
        let mut current_offset = block_offset;
        let mut data_offset = 0;
        
        while data_offset < data.len() {
            let (member_index, member_offset) = self.locate_block(current_offset);
            let member = &self.array.members[member_index];
            
            if member.status != MemberStatus::Online {
                return Err("Member offline".into());
            }
            
            let chunk_size = std::cmp::min(
                self.array.stripe_size as usize,
                data.len() - data_offset
            );
            
            let file = std::fs::OpenOptions::new()
                .write(true)
                .open(&member.device_path)?;
            use std::io::{Write, Seek};
            let mut file = file;
            file.seek(std::io::SeekFrom::Start(member_offset + current_offset % self.array.stripe_size))?;
            file.write_all(&data[data_offset..data_offset + chunk_size])?;
            
            current_offset += chunk_size as u64;
            data_offset += chunk_size;
        }
        
        Ok(())
    }
    
    fn get_total_size(&self) -> u64 {
        self.array.total_size
    }
    
    fn get_level(&self) -> RaidLevel {
        RaidLevel::RAID0
    }
}