#!/usr/bin/env python3
"""
WST ETC - Command-Line Interface

Call the WST Exposure Time Calculator backend through its JSON API.
Print the resulting JSON on stdout or optionally to a file.

Typical use:
    1. Use the "Save Configuration" button on the WST ETC web interface
       to download a JSON configuration file (wst_etc_config.json)
    2. Adjust parameter values in the JSON file as needed
    3. Run this script to call the ETC backend API:

       python wst_cli.py wst_etc_config.json -o results.json -i 4

Note: The API has minimal input parameter validation.
Valid parameter ranges and combinations can be found on the web interface.
"""

import sys
import os
import json
import argparse
import requests


def collapse(jsondata):
    """Collapse large numeric arrays to short summary strings for readable output."""
    def go_through(x):
        if isinstance(x, list):
            return go_through_list(x)
        elif isinstance(x, dict):
            return go_through_dict(x)
        return x

    def go_through_dict(dic):
        for key, value in dic.items():
            if isinstance(value, dict):
                dic[key] = go_through_dict(value)
            elif isinstance(value, list):
                dic[key] = go_through_list(value)
        return dic

    def go_through_list(lst):
        if all(isinstance(y, (int, float)) for y in lst):
            if len(lst) <= 2:
                return lst
            return f'[{lst[0]} ... {lst[-1]}] ({len(lst)} points)'
        return [go_through(y) for y in lst]

    return go_through_dict(jsondata)


def main():
    parser = argparse.ArgumentParser(
        description='Call the WST ETC backend API with JSON input parameters.\n'
                    'Print the resulting JSON on stdout or optionally to a file.\n\n'
                    'Examples:\n'
                    '  python wst_cli.py config.json\n'
                    '  python wst_cli.py config.json -o results.json\n'
                    '  python wst_cli.py config.json -i 4 -c\n'
                    '  python wst_cli.py config.json -s http://myserver:5001',
        formatter_class=argparse.RawTextHelpFormatter
    )

    parser.add_argument('configfile',
                        help='JSON file with ETC input parameters\n'
                             '(from the web interface "Save Configuration" button)')

    parser.add_argument('-c', '--collapse', action='store_true',
                        help='collapse output JSON data arrays to short indicative strings')

    parser.add_argument('-i', '--indent', type=int, nargs='?', const=4,
                        help='format the output JSON with indentation (default: 4)')

    parser.add_argument('-o', '--outputfile', dest='outputfile',
                        help='save the output to file instead of stdout')

    parser.add_argument('-f', '--spectrum-file', dest='spectrum_file',
                        help='spectrum file to upload (for Obj_SED=upload).\n'
                             'Supported formats:\n'
                             '  - ASCII: two columns (wavelength, flux),\n'
                             '    optional header comments: # nm/aa (wave unit), # fl/ph (flux unit)\n'
                             '  - FITS: BINTABLE with wavelength+flux columns,\n'
                             '    or 1D IMAGE HDU with WCS wavelength axis')

    parser.add_argument('-s', '--server', dest='server',
                        default='http://192.167.39.206',
                        help='WST ETC server URL (default: http://192.167.39.206)')

    args = parser.parse_args()

    # Read input configuration
    try:
        with open(args.configfile) as f:
            config = json.load(f)
    except OSError as e:
        print(f'Cannot open {args.configfile}: {e}', file=sys.stderr)
        sys.exit(1)
    except json.JSONDecodeError as e:
        print(f'Invalid JSON in {args.configfile}: {e}', file=sys.stderr)
        sys.exit(1)

    # Validate spectrum file options
    if args.spectrum_file:
        if not os.path.isfile(args.spectrum_file):
            print(f'Error: spectrum file not found: {args.spectrum_file}', file=sys.stderr)
            sys.exit(1)
        if config.get('Obj_SED') != 'upload':
            print(f'Warning: -f given but Obj_SED is "{config.get("Obj_SED", "not set")}", '
                  f'setting Obj_SED to "upload"', file=sys.stderr)
            config['Obj_SED'] = 'upload'
    elif config.get('Obj_SED') == 'upload':
        print('Error: Obj_SED is "upload" but no spectrum file given (use -f)', file=sys.stderr)
        sys.exit(1)

    # Build API URL
    url = args.server.rstrip('/') + '/api/compute'

    # Call the API
    try:
        if args.spectrum_file:
            # Multipart upload: JSON config + spectrum file
            with open(args.spectrum_file, 'rb') as sf:
                response = requests.post(
                    url,
                    data={'config': json.dumps(config)},
                    files={'spectrum_file': (args.spectrum_file, sf)},
                    timeout=300
                )
        else:
            response = requests.post(url, json=config, timeout=300)
        response.raise_for_status()
        result = response.json()
    except requests.exceptions.ConnectionError:
        print(f'Error: cannot connect to {args.server}', file=sys.stderr)
        print('Make sure the WST ETC server is running.', file=sys.stderr)
        sys.exit(1)
    except requests.exceptions.Timeout:
        print('Error: request timed out (300s limit)', file=sys.stderr)
        sys.exit(1)
    except requests.exceptions.HTTPError as e:
        print(f'HTTP error: {e}', file=sys.stderr)
        try:
            err = response.json()
            print(f'Server message: {err.get("message", "")}', file=sys.stderr)
        except Exception:
            pass
        sys.exit(1)
    except Exception as e:
        print(f'Error: {e}', file=sys.stderr)
        sys.exit(1)

    # Process output
    if args.collapse:
        result = collapse(result)

    output_text = json.dumps(result, indent=args.indent)

    if args.outputfile:
        with open(args.outputfile, 'w') as f:
            f.write(output_text + '\n')
        print(f'Output saved to {args.outputfile}', file=sys.stderr)
    else:
        print(output_text)


if __name__ == '__main__':
    main()
