//! Core library for Krira Augment
//! 
//! Implements high-performance parallel file processing.

use std::fs::File;
use std::io::{BufWriter, Write};
use std::sync::{Arc, Mutex};

use memmap2::MmapOptions;
use pyo3::prelude::*;
use rayon::prelude::*;
use serde::{Deserialize, Serialize};

mod cleaning;
mod chunker;
mod errors;

use cleaning::RustCleaner;
use chunker::RustChunker;
use errors::KriraError;

// =============================================================================
// structs
// =============================================================================

#[derive(Serialize, Deserialize)]
struct PipelineConfig {
    max_chars: usize,
}

#[derive(Serialize)]
struct ChunkObj {
    text: String,
    length: usize,
}

// =============================================================================
// Core Function
// =============================================================================

/// Process a file in parallel using Rust.
/// 
/// 1. Maps file to memory (Zero-copy read)
/// 2. Iterates lines in parallel (Rayon)
/// 3. Cleans and Chunks lines
/// 4. Writes results to output file
#[pyfunction]
fn process_file_rust(py: Python, input_path: String, output_path: String, config_json: String) -> PyResult<()> {
    
    // 1. Parse Config
    let config: PipelineConfig = serde_json::from_str(&config_json)
        .map_err(|e| KriraError::ConfigError(e.to_string()))?;
        
    let chunker = RustChunker::new(config.max_chars);

    // 2. Prepare Output Writer (Thread-safe)
    let output_file = File::create(&output_path).map_err(KriraError::IOError)?;
    let writer = Arc::new(Mutex::new(BufWriter::new(output_file)));

    // 3. Release GIL for heavy lifting
    py.allow_threads(move || -> Result<(), KriraError> {
        // Open File
        let file = File::open(&input_path).map_err(KriraError::IOError)?;
        
        // Mmap
        // unsafe block required for mmap, assuming file is not modified concurrently
        let mmap = unsafe { MmapOptions::new().map(&file).map_err(KriraError::IOError)? };
        
        // Convert to str (assumes UTF-8)
        // If file is huge and not perfectly UTF-8, this might fail or check the whole file.
        // For strict performance on strict UTF-8 files, strict slice is fast.
        let content = std::str::from_utf8(&mmap[..])
            .map_err(|e| KriraError::ConfigError(format!("File is not valid UTF-8: {}", e)))?;

        // Parallel Processing
        // We split by lines. If it's a huge CSV/JSONL, lines are individual records.
        content.par_lines()
            .for_each(|line| {
                if line.trim().is_empty() { return; }

                // Clean
                let cleaned = RustCleaner::clean(line);
                if cleaned.is_empty() { return; }

                // Chunk
                let chunks = chunker.chunk(&cleaned);

                // Serialize Results
                let results: Vec<ChunkObj> = chunks.into_iter().map(|c| ChunkObj {
                    length: c.len(),
                    text: c,
                }).collect();

                // Write to disk (Critical Section)
                if !results.is_empty() {
                   if let Ok(mut w) = writer.lock() {
                       for res in results {
                           if let Ok(json_line) = serde_json::to_string(&res) {
                               let _ = writeln!(w, "{}", json_line);
                           }
                       }
                   }
                }
            });

        Ok(())
    }).map_err(PyErr::from)
}

// =============================================================================
// Python Module
// =============================================================================

#[pymodule]
fn _rust(m: &Bound<'_, PyModule>) -> PyResult<()> {
    m.add_function(wrap_pyfunction!(process_file_rust, m)?)?;
    Ok(())
}
