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

use tempfile::TempDir;

use crate::bitvec::{PersistentBitVec, PersistentBitVecBuilder};
use crate::views::{BitSliceIter, BitSliceView, IntSliceView};

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

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

impl TempBitVec {
    pub fn make_persistent(&self, path: &Path) -> io::Result<PersistentBitVec> {
        std::fs::copy(self.vec.path(), path)?;
        PersistentBitVec::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) -> bool {
        self.vec.get(slot)
    }
    pub fn count_ones(&self) -> u64 {
        self.vec.count_ones()
    }
    pub fn view(&self) -> BitSliceView<'_> {
        self.vec.view()
    }
    pub fn iter(&self) -> BitSliceIter<'_> {
        self.view().iter()
    }
}

// ── TempBitVecBuilder — mutable, becomes TempBitVec on freeze ────────────────

pub struct TempBitVecBuilder {
    builder: PersistentBitVecBuilder,
    temp: TempDir,
}

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

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

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

    pub fn set(&mut self, slot: usize, value: bool) {
        self.builder.set(slot, value);
    }

    pub fn view(&self) -> BitSliceView<'_> {
        self.builder.view()
    }

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

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

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

    pub fn not(&mut self) {
        self.builder.not();
    }

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

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

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

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