from __future__ import annotations

import logging
import time
from pathlib import Path
from typing import Any
import shutil

from phenomate_core.preprocessing.base import BasePreprocessor

# shared_logger = logging.getLogger("celery")
from phenomate_core.get_version import get_task_logger
shared_logger = get_task_logger(__name__)

class RS3Preprocessor(BasePreprocessor[Path]):
    """
    Code based
    
    """
    
    def __init__(self, path: str | Path, in_ext: str = "bin", **kwargs: Any):
        super().__init__(path, in_ext)   # pass parameters up to Base


    def extract(self, **kwargs: Any) -> None:
        """
        This method reads the '.origin' file extended version of the .bin file selected and
        reads the source directory (the directory where the .bin file was selected in the
        Phenomate GUI) and looks for files of the same name and timestamp to select and stores
        this as a list of filenames in the self.images list, to be processed in the save() method.
        """

        dir_part = self.path.parent  # this is another Path type
        file_part = self.path.name  # this is a str

        # Read the path that was written to the self.path+'.origin' file        
        origin_path = self.open_origin_file()  
        # Select the matching files from the path by the timestamp of the self.path file
        path_objects = self.matched_file_list(origin_path, file_part)
        
        for file_path in path_objects:
            shared_logger.info(f"RS3Preprocessor data transfer: file_path.suffix:  {file_path.suffix}")
            if file_path.suffix == ".25O":
                self.extra_files.append(file_path)
            elif file_path.suffix == ".25P":
                self.extra_files.append(file_path)
                
        shared_logger.info(f"RS3Preprocessor data transfer: number of related files:  {len(self.extra_files)}")
        # self.images = path_objects

    def copy_extra_files(self, fpath: Path) -> None:
        """
        Extra files that are associated with the RS3 (IMU Basestation) .25B data will be copied 
        to the destination directory.
        
        :fpath Path: is the directory in which to save the files
        
        This method impicitly uses the extra_files list that should be populated in the extract() method using
        open_origin_file() and matched_file_list() (see: RS3Preprocessor.extract())
        
        
        """
        for file_path in self.extra_files:
            try:
                # For the RS3 there should be 3 files .25B, .25O, .25P 
                if file_path.suffix == ".25O":
                    file_path_name_ext = fpath / self.get_output_name(
                        index=None, ext="25O", details=None
                    )
                elif file_path.suffix == ".25P":
                    file_path_name_ext = fpath / self.get_output_name(
                        index=None, ext="25P", details=None
                    )
                    
                    
                shutil.copy(file_path, file_path_name_ext)
                shared_logger.info(f"RS3Preprocessor.copy_extra_files(): RS3 data transfer: Copied file: {file_path_name_ext}")

            except FileNotFoundError as e:
                shared_logger.error(f"RS3Preprocessor: data transfer: File not found: {file_path} — {e}")
            except PermissionError as e:
                shared_logger.error(f"RS3Preprocessor: data transfer: Permission denied: {file_path} — {e}")
            except OSError as e:
                shared_logger.error(f"RS3Preprocessor: data transfer: OS error while accessing {file_path}: {e}")
            except Exception as e:
                shared_logger.exception(f"RS3Preprocessor: data transfer: Unexpected error while reading {file_path}: {e}")
                raise
                
    def matched_file_list(self, origin_path: Path, file_part : str) -> list[Path]:

        """
        Return a list of files from the source directory that match the timstamp of the :path: file.
        """
        # Set of all files in the directory
        files_in_dir = self.list_files_in_directory(origin_path.parent)
        shared_logger.info(f"RS3Preprocessor: files_in_dir:  {files_in_dir}")
        
        # Set the timestamp regular expression
        filestamp = r'(\d{14})'  # Added to the *end* of the file as RS3 data is downloaded seperately
        # Match the filename timestamps to the input filename
        matched = self.match_timestamp(file_part, files_in_dir, filestamp)
        shared_logger.info(f"RS3Preprocessor: Matched files: {matched}")
        # Add back the directory
        matched_with_dir = [origin_path.parent / f for f in matched]
        # Save the list of matched filenames to extra_files list to be used
        # in the save() method. Conver t he strings to Path objects        
        path_objects = [Path(p) for p in matched_with_dir]
        return path_objects
        
            
    def save(
        self,
        path: Path | str,
        **kwargs: Any,
    ) -> None:
        """
        Save the data files from the RS3 Base station
        The first file is ".25B", which s copied by the backend to the output directry.
        The following ".25O" and ".25P" files are copied using the "matched_files_list()" method
        """
        fpath = Path(path)
        fpath.mkdir(parents=True, exist_ok=True)

        # current_year = str(datetime.now(timezone.utc).year)
        # phenomate_version = get_version()
        start_time = time.time()

        self.copy_extra_files(fpath)

        # End timer
        end_time = time.time()
        # Print elapsed time
        shared_logger.info(f"RS3Preprocessor: Write time: {end_time - start_time:.4f} seconds")
