"""
Identifier:     csst-l1/msc/csst_msc_instrument/csst_msc_instrument/format.py
Name:           format.py
Description:    Data format conversion.
Author:         Li Shao (shaoli@nao.cas.cn)
Created:        2023-11-16
Modified-History:
    2023-11-16, Li Shao, created
    2023-11-22, Li Shao, split from common_detector
    2023-11-23, Li Shao, change the way to get CCDArrayConfig
    2023-12-21, Li Shao, add function convert_format_one_cube
    2024-02-06, Li Shao, move to csst_msc_instrument
    2024-03-05, Li Shao, merge all three functions into one
"""

import numpy as np

from .config import get_array_config

__all__ = ["convert_format", ]


def convert_format(image: np.ndarray,
                   output_format: str,
                   array_config_name: str = 'CCDArrayConfig',
                   ) -> np.ndarray:
    """
    Convert image format.

    The function will automatically detect input format and convert to the output format.
    The output format includes: "raw", "cube", "sky".

    Parameters
    ----------
    image : numpy.ndarray
        Input 2-D image.
    output_format : str
        The output format name: "raw", "cube" or "sky".
    array_config_name : str, optional
        The name of the pixel array configuration class. Default is "CCDArrayConfig".

    Returns
    -------
    numpy.ndarray
        Converted image. If convert from "sky" to other format, non-active region will be filled with 0.
    """

    config = get_array_config(array_config_name)
    conf_raw = config('raw')
    conf_cube = config('cube')
    conf_sky = config('sky')
    shape_input = image.shape
    if np.array_equal(shape_input, conf_raw.get_shape(full=True)):
        iconf = conf_raw
    elif np.array_equal(shape_input, conf_cube.get_shape(full=True)):
        iconf = conf_cube
    elif np.array_equal(shape_input, conf_sky.get_shape(full=True)):
        iconf = conf_sky
    else:
        raise ValueError('Input data shape is inconsistent with array configuration.')

    if output_format == 'raw':
        oconf = conf_raw
    elif output_format == 'cube':
        oconf = conf_cube
    elif output_format == 'sky':
        oconf = conf_sky
    else:
        raise ValueError('Invalid output type: "{}". Must be "raw", "cube" or "sky".'.format(output_format))

    if iconf == oconf:
        print('Warning: input and output is the same. No format conversion is performed.')
        return image

    if iconf.image_format == 'sky' or output_format == 'sky':
        rtype = 'active'
    else:
        rtype = 'channel'
    oshape = oconf.get_shape(full=True)
    output = np.zeros(oshape, dtype=image.dtype)
    for i in range(iconf.nchan):
        cutout = iconf.get_cutout(i+1, image, rtype=rtype)
        oconf.set_cutout(i+1, output, cutout, rtype=rtype)

    return output
