"""Command line script to list simple stats of multiple images"""

import sys
import os
import time

import numpy as np

from trm import cline
from trm.cline import Cline

import hipercam as hcam
from hipercam import spooler

__all__ = [
    "mstats",
]

##################################################################
#
# mstats -- lists stats of a series of images from a raw data file
#
##################################################################


def mstats(args=None):
    """``mstats [source] run [temp] (ndigit) first last [twait tmax] bias
    [dtype]``

    This downloads a sequence of images from a raw data file and writes 
    out stats (min, max, mean, median, rms) for each window to a file

    Parameters:

       source  : string [hidden]
           Data source, four options:

              | 'hs' : HiPERCAM server
              | 'hl' : local HiPERCAM FITS file
              | 'us' : ULTRACAM server
              | 'ul' : local ULTRACAM .xml/.dat files

       run     : string
           run name to access

       first   : int
           First frame to access

       last    : int
           Last frame to access, 0 for the lot

       twait   : float [hidden]
           time to wait between attempts to find a new exposure, seconds.

       tmax    : float [hidden]
           maximum time to wait between attempts to find a new exposure,
           seconds.

       bias    : string
           Name of bias frame to subtract, 'none' to ignore.

       format  : string
           output format for numbers. e.g. the default '9.3f'
           might give 12345.678 (9 characters, 3 digits after d.p.)

       outfile : string
           file for output (extension .stats)

    """

    command, args = cline.script_args(args)

    # get inputs
    with Cline("HIPERCAM_ENV", ".hipercam", command, args) as cl:

        # register parameters
        cl.register("source", Cline.GLOBAL, Cline.HIDE)
        cl.register("run", Cline.GLOBAL, Cline.PROMPT)
        cl.register("first", Cline.LOCAL, Cline.PROMPT)
        cl.register("last", Cline.LOCAL, Cline.PROMPT)
        cl.register("twait", Cline.LOCAL, Cline.HIDE)
        cl.register("tmax", Cline.LOCAL, Cline.HIDE)
        cl.register("bias", Cline.GLOBAL, Cline.PROMPT)
        cl.register("format", Cline.LOCAL, Cline.HIDE)
        cl.register("outfile", Cline.LOCAL, Cline.PROMPT)

        # get inputs
        source = cl.get_value(
            "source",
            "data source [hs, hl, us, ul]",
            "hl",
            lvals=("hs", "hl", "us", "ul"),
        )

        # OK, more inputs
        resource = cl.get_value("run", "run name", "run005")

        first = cl.get_value("first", "first frame to grab", 1, 0)
        last = cl.get_value("last", "last frame to grab", 0)
        if last < first and last != 0:
            sys.stderr.write("last must be >= first or 0")
            sys.exit(1)

        twait = cl.get_value("twait", "time to wait for a new frame [secs]", 1.0, 0.0)
        tmax = cl.get_value(
            "tmax", "maximum time to wait for a new frame [secs]", 10.0, 0.0
        )

        bias = cl.get_value(
            "bias",
            "bias frame ['none' to ignore]",
            cline.Fname("bias", hcam.HCAM),
            ignore="none",
        )

        cl.set_default("format", "9.3f")
        form = cl.get_value("format", "output format for stats", "9.3f")

        outfile = cl.get_value(
            "outfile",
            "output file for stats",
            cline.Fname("stats", ".stats", cline.Fname.NEW),
        )

    # Now the actual work.

    # strip off extensions
    if resource.endswith(hcam.HRAW):
        resource = resource[: resource.find(hcam.HRAW)]

    # initialisations
    total_time = 0  # time waiting for new frame
    nframe = first
    root = os.path.basename(resource)
    bframe = None

    with spooler.data_source(source, resource, first) as spool:

        with open(outfile, "w") as stats:

            stats.write(
                """#
# This file was generated by mstats running on file {run}
#
# The columns are:
#
# nframe ccd window minimum maximum mean median rms
#
# where ccd and window are string labels, nframe is the frame
# number an an integer, while the rest are floats.
#
""".format(
                    run=resource
                )
            )

            for mccd in spool:

                # Handle the waiting game ...
                give_up, try_again, total_time = spooler.hang_about(
                    mccd, twait, tmax, total_time
                )

                if give_up:
                    print("mstats stopped")
                    break
                elif try_again:
                    continue

                if bias is not None:
                    # read bias after first frame so we can
                    # chop the format
                    if bframe is None:

                        # read the bias frame
                        bframe = hcam.MCCD.read(bias)

                        # reformat
                        bframe = bframe.crop(mccd)

                    mccd -= bframe

                for cnam, ccd in mccd.items():
                    for wnam, wind in ccd.items():
                        stats.write(
                            (
                                "{1:5d}   {2:5s} {3:5s} {4:{0:s}} {5:{0:s}}"
                                " {6:{0:s}} {7:{0:s}} {8:{0:s}}\n"
                            ).format(
                                form,
                                nframe,
                                cnam,
                                wnam,
                                wind.min(),
                                wind.max(),
                                wind.mean(),
                                wind.median(),
                                wind.std(),
                            )
                        )

                # flush the output
                stats.flush()

                # progress info
                print("Written stats of frame {:d} to {:s}".format(nframe, outfile))

                # update the frame number
                nframe += 1
                if last and nframe > last:
                    break
