use std::ops::RangeInclusive;

use camino::Utf8PathBuf;
use libpijul::pristine::sanakirja::SanakirjaError;

use crate::file_system::changes::unrecorded::UnrecordedChangesError;
use crate::file_system::changes::{CreditSource, FileCredits, FileCreditsError, Span};
use crate::file_system::open_file::contents::FileContents;

pub mod contents;

#[derive(Debug, thiserror::Error)]
pub enum OpenFileError<C: std::error::Error + 'static, W: std::error::Error + 'static> {
    #[error("failed to check if {path} is tracked: {error:#?}")]
    CheckIfTracked {
        path: Utf8PathBuf,
        error: SanakirjaError,
    },
    #[error(transparent)]
    FileChanges(#[from] UnrecordedChangesError<C, W>),
    #[error(transparent)]
    TrackedFile(#[from] FileCreditsError<C, W>),
}

#[derive(Clone, Debug)]
pub struct OpenFile {
    pub contents: FileContents,
    // TODO: use more structured representation for tracked vs untracked files
    pub credits: Option<FileCredits>,
}

impl OpenFile {
    pub fn credit(&self, lines: RangeInclusive<usize>) -> Vec<Span<CreditSource>> {
        match &self.credits {
            Some(credits) => credits.spans_within_lines(lines).collect(),
            None => Vec::new(),
        }
    }

    pub fn tracked_contents(&self) -> Option<&str> {
        let credits = self.credits.as_ref()?;

        Some(&credits.recorded_state.original_contents)
    }
}