//! Legacy JSONL storage backend
//!
//! Wraps the existing `DocumentStore` as a `StorageBackend` implementation,
//! ensuring backward compatibility when the Lance storage feature is not
//! enabled or when working with existing JSONL data.

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

use crate::types::MemoryNode;
use super::backend::{StorageBackend, StorageError, StorageResult, QueryFilter};
use super::document::DocumentStore;

/// Legacy storage backend backed by JSONL files.
///
/// This is a thin wrapper around `DocumentStore` that implements the
/// `StorageBackend` trait, allowing it to be used interchangeably
/// with the Lance backend.
pub struct LegacyStorageBackend {
    store: DocumentStore,
}

impl LegacyStorageBackend {
    /// Create a new legacy backend at the given path.
    pub fn new(path: impl AsRef<Path>) -> StorageResult<Self> {
        let store = DocumentStore::open_or_create(path)?;
        Ok(Self { store })
    }

    /// Open an existing store or create a new one (alias for `new`).
    pub fn open_or_create(path: impl AsRef<Path>) -> io::Result<Self> {
        let store = DocumentStore::open_or_create(path)?;
        Ok(Self { store })
    }

    /// Get a reference to the inner `DocumentStore`.
    pub fn inner(&self) -> &DocumentStore {
        &self.store
    }
}

impl StorageBackend for LegacyStorageBackend {
    fn put(&self, node: MemoryNode) -> StorageResult<()> {
        self.store.put(node).map_err(|e| {
            if e.kind() == io::ErrorKind::InvalidInput {
                StorageError::InvalidId(e.to_string())
            } else {
                StorageError::Io(e)
            }
        })
    }

    fn get(&self, id: &str) -> StorageResult<Option<MemoryNode>> {
        Ok(self.store.get(id))
    }

    fn delete(&self, id: &str) -> StorageResult<Option<MemoryNode>> {
        Ok(self.store.delete(id))
    }

    fn contains(&self, id: &str) -> StorageResult<bool> {
        Ok(self.store.contains(id))
    }

    fn ids(&self) -> StorageResult<Vec<String>> {
        Ok(self.store.ids())
    }

    fn len(&self) -> StorageResult<usize> {
        Ok(self.store.len())
    }

    fn all(&self) -> StorageResult<Vec<MemoryNode>> {
        Ok(self.store.all())
    }

    fn query(&self, filter: &QueryFilter) -> StorageResult<Vec<MemoryNode>> {
        // For simple single-filter cases without sorting/offset/metadata,
        // use DocumentStore's native optimized methods
        let has_advanced = filter.metadata.is_some()
            || filter.sort_by.is_some()
            || filter.offset > 0;

        if !has_advanced {
            // Fast path: single tag filter
            if filter.tags.is_some()
                && filter.content_type.is_none()
                && filter.parent_id.is_none()
                && filter.min_importance.is_none()
                && filter.time_range.is_none()
            {
                let tags = filter.tags.as_ref().unwrap();
                let mut results = Vec::new();
                for tag in tags {
                    results.extend(self.store.find_by_tag(tag));
                }
                results.sort_by(|a, b| a.id.cmp(&b.id));
                results.dedup_by(|a, b| a.id == b.id);
                if filter.limit > 0 && results.len() > filter.limit {
                    results.truncate(filter.limit);
                }
                return Ok(results);
            }

            // Fast path: single content_type filter
            if filter.content_type.is_some()
                && filter.tags.is_none()
                && filter.parent_id.is_none()
                && filter.min_importance.is_none()
                && filter.time_range.is_none()
            {
                let mut results = self.store.find_by_content_type(filter.content_type.unwrap());
                if filter.limit > 0 && results.len() > filter.limit {
                    results.truncate(filter.limit);
                }
                return Ok(results);
            }

            // Fast path: single parent_id filter
            if filter.parent_id.is_some()
                && filter.tags.is_none()
                && filter.content_type.is_none()
                && filter.min_importance.is_none()
                && filter.time_range.is_none()
            {
                let mut results = self.store.find_by_parent(filter.parent_id.as_deref().unwrap());
                if filter.limit > 0 && results.len() > filter.limit {
                    results.truncate(filter.limit);
                }
                return Ok(results);
            }
        }

        // Fall back to the default trait implementation for complex/advanced filters
        // This handles metadata, sorting, offset, and combined filters
        let mut results = self.all()?;

        if let Some(ref tags) = filter.tags {
            results.retain(|node| tags.iter().any(|tag| node.tags.contains(tag)));
        }
        if let Some(content_type) = filter.content_type {
            results.retain(|node| node.content_type == content_type);
        }
        if let Some(ref parent_id) = filter.parent_id {
            results.retain(|node| node.parent_id.as_deref() == Some(parent_id.as_str()));
        }
        if let Some(min_importance) = filter.min_importance {
            results.retain(|node| node.computed_importance() >= min_importance);
        }
        if let Some((start, end)) = filter.time_range {
            results.retain(|node| node.created_at >= start && node.created_at <= end);
        }
        if let Some(ref metadata_filters) = filter.metadata {
            results.retain(|node| {
                metadata_filters.iter().all(|mf| node.metadata.get(&mf.key) == Some(&mf.value))
            });
        }

        // Apply sorting
        if let Some(sort_by) = filter.sort_by {
            use super::backend::{SortField, SortOrder};
            match sort_by {
                SortField::CreatedAt => results.sort_by(|a, b| a.created_at.cmp(&b.created_at)),
                SortField::LastAccessedAt => results.sort_by(|a, b| a.last_accessed_at.cmp(&b.last_accessed_at)),
                SortField::Importance => results.sort_by(|a, b| {
                    a.computed_importance().partial_cmp(&b.computed_importance()).unwrap_or(std::cmp::Ordering::Equal)
                }),
                SortField::AccessCount => results.sort_by(|a, b| a.access_count.cmp(&b.access_count)),
            }
            if filter.sort_order == SortOrder::Desc {
                results.reverse();
            }
        }

        // Apply offset
        if filter.offset > 0 {
            if filter.offset >= results.len() {
                return Ok(Vec::new());
            }
            results = results.split_off(filter.offset);
        }

        // Apply limit
        if filter.limit > 0 && results.len() > filter.limit {
            results.truncate(filter.limit);
        }

        Ok(results)
    }

    fn record_access(&self, id: &str) -> StorageResult<()> {
        self.store.record_access(id).ok_or_else(|| {
            StorageError::NotFound(id.to_string())
        })
    }

    fn flush(&self) -> StorageResult<()> {
        self.store.flush().map_err(StorageError::Io)
    }

    fn backend_name(&self) -> &str {
        "jsonl"
    }
}
