# Source code for noctua.utils.structure

    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-

    """
    Functions managing the several directory names.
    """

    # System modules
    import shutil
    from pathlib import Path

    # Third-party modules
    from astropy.io import fits
    from astropy.time import Time

    # Other templates
    from ..config.constants import (DATA_FOLDER, FILE_PREFIX, FITS_EXT,
                                    FITS_FOLDER, FOCUS_EXT, FOCUS_FOLDER, LOG_EXT,
                                    LOG_FOLDER, dateobs, dir_type, frame_number,
                                    imagetyp)

    PROJECT_ROOT = Path(__file__).parent.parent.parent

    def date_folder():
        """Create a date folder string based on astronomical convention
        (changes at midday UTC).
        """
        now = Time.now()
        # If current UTC hour is before midday UTC, the "observing night"
        # belongs to the previous calendar date.
        if now.datetime.hour < 12:
            folder_date_obj = now.datetime.date() - timedelta(days=1)
        else:
            folder_date_obj = now.datetime.date()
        return folder_date_obj.strftime("%Y-%m-%d")

    def frame_folder(header):
        """
        Create a folder depending on the image type in FITS header
        """
        frame = header[imagetyp]
        if isinstance(frame, int):
            folder_name = dir_type[frame]
        else:
            frame_num_list = [v for k, v in frame_number.items() if k in frame]
            if not frame_num_list:
                # Fallback if frame type string is not recognized
                return "unknown_type"
            folder_name = dir_type[frame_num_list[0]]
        return folder_name

    def fits_path(header, dry=False):
        """
        Create a fits file path where the file will be stored
        """

        root = PROJECT_ROOT / DATA_FOLDER / FITS_FOLDER

        date_str = date_folder()
        date_path_part = Path(date_str)

        frame_path_part = Path(frame_folder(header))
        path = root / date_path_part / frame_path_part

        if not dry:
            path.mkdir(parents=True, exist_ok=True)
        return path

    def log_path(dry=False):
        """
        Returns the Path object for the log directory.
        Creates it if it doesn't exist (unless dry=True).
        """

        path = PROJECT_ROOT / DATA_FOLDER / LOG_FOLDER

        if not dry:
            path.mkdir(parents=True, exist_ok=True)

        # OARPAF.YYYY-MM-DD.foc
        outfile = f"{FILE_PREFIX}.{LOG_EXT}"
        outpath = path / outfile
        return outpath

        return outpath

    def foc_path(timestamp, dry=False):
        """
        Create the focus output text file name and its path
        """

        path = PROJECT_ROOT / DATA_FOLDER / FOCUS_FOLDER

        if not dry:
            path.mkdir(parents=True, exist_ok=True)

        # OARPAF.YYYY-MM-DD.foc
        outfile = f"{FILE_PREFIX}.{timestamp}.{FOCUS_EXT}"
        outpath = path / outfile
        return outpath

    def save_filename(infile_path_str):
        """
        Save a fits file in its path with an ESO-style filename.
        """

        inpath = Path(infile_path_str)
        header = fits.getheader(inpath)

        # '2021-12-28T20:09:56.163'
        date_obs_str = header[dateobs]  # DATE-OBS from FITS header
        name_for_file = Time(date_obs_str).isot

        outfile_name = f"{FILE_PREFIX}.{name_for_file}.{FITS_EXT}"
        outfile = Path(outfile_name)

        outdir = fits_path(header)  # This already creates the directory
        outpath = outdir / outfile

        shutil.copy2(inpath, outpath)
        return str(outpath)