use std::io;
use std::path::Path;

use tempfile::TempDir;

use crate::builder::PersistentCompactIntVecBuilder;
use crate::reader::PersistentCompactIntVec;
use crate::views::{BitSliceView, IntSliceView};

// ── TempCompactIntVec — frozen read-only, auto-deleted on drop ────────────────

pub struct TempCompactIntVec {
    vec:   PersistentCompactIntVec,
    // Dropped after `vec` (field order), so the mmap is released before the
    // temp directory is deleted.
    _temp: TempDir,
}

impl TempCompactIntVec {
    pub fn make_persistent(&self, path: &Path) -> io::Result<PersistentCompactIntVec> {
        std::fs::copy(self.vec.path(), path)?;
        PersistentCompactIntVec::open(path)
    }

    pub fn len(&self)      -> usize { self.vec.len() }
    pub fn is_empty(&self) -> bool  { self.vec.is_empty() }
    pub fn get(&self, slot: usize) -> u32  { self.vec.get(slot) }
    pub fn sum(&self)      -> u64   { self.vec.sum() }
    pub fn view(&self)     -> IntSliceView<'_> { self.vec.view() }
    pub fn iter(&self) -> crate::reader::Iter<'_> { self.vec.iter() }
}

// ── TempCompactIntVecBuilder — mutable, becomes TempCompactIntVec on freeze ──

pub struct TempCompactIntVecBuilder {
    builder: PersistentCompactIntVecBuilder,
    temp:    TempDir,
}

impl TempCompactIntVecBuilder {
    pub fn new(n: usize) -> io::Result<Self> {
        let temp = TempDir::new()?;
        let path = temp.path().join("data.pciv");
        let builder = PersistentCompactIntVecBuilder::new(n, &path)?;
        Ok(Self { builder, temp })
    }

    pub fn freeze(self) -> io::Result<TempCompactIntVec> {
        let Self { builder, temp } = self;
        let vec = builder.finish()?;
        Ok(TempCompactIntVec { vec, _temp: temp })
    }

    pub fn n(&self) -> usize { self.builder.len() }

    pub fn set(&mut self, slot: usize, value: u32) { self.builder.set(slot, value); }
    pub fn get(&self, slot: usize) -> u32           { self.builder.get(slot) }

    pub fn primary_bytes(&self)         -> &[u8]      { self.builder.primary_bytes() }
    pub fn primary_bytes_mut(&mut self) -> &mut [u8]  { self.builder.primary_bytes_mut() }

    pub fn inc_present(&mut self, col: BitSliceView<'_>) {
        self.builder.inc_present(col);
    }

    pub fn inc_present_fast(&mut self, col: BitSliceView<'_>) {
        self.builder.inc_present_fast(col);
    }

    pub fn inc_predicate(&mut self, col: IntSliceView<'_>, pred: impl Fn(u32) -> bool) {
        self.builder.inc_predicate(col, pred);
    }

    pub fn inc_predicate_fast(&mut self, col: IntSliceView<'_>, pred: impl Fn(u32) -> bool) {
        self.builder.inc_predicate_fast(col, pred);
    }

    pub fn add(&mut self, other: IntSliceView<'_>) {
        self.builder.add(other);
    }

    pub fn mask_with(&mut self, mask: BitSliceView<'_>) {
        self.builder.mask_with(mask);
    }

    pub fn min(&mut self, other: IntSliceView<'_>)  { self.builder.min(other); }
    pub fn max(&mut self, other: IntSliceView<'_>)  { self.builder.max(other); }
    pub fn diff(&mut self, other: IntSliceView<'_>) { self.builder.diff(other); }
}
