#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2021 Samsung Electronics.Co.Ltd.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; version 2 of the License
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
# for more details.

"""Generate basic information"""

import os
import sys
import shutil
import time
import json
import subprocess

from datetime import datetime

from bsr.utility.utils import json_datetime_serializer, console, pushd
from bsr.utility.monitoring import Monitoring


def gather_meta_information(user_log_dir, build_time, ref_build_time):
    """Meta information of the build"""

    meta = {
        'BuildDetail':
            {
                'Total': 0, 'Pass': 0, 'Fail': 0, 'RunTime': 0, 'StartTime': 0, 'EndTime': 0
            },
        'ReferenceDetail':
            {
                'Total': 0, 'Pass': 0, 'Fail': 0, 'RunTime': 0, 'StartTime': 0, 'EndTime': 0
            }
    }

    def to_timestamp(date_obj):
        """Convert to string to datetime object"""

        return int(time.mktime(date_obj.timetuple()) * 1000)

    def get_first_end_time(source):
        """Get the first and end time from build data"""

        start_time = 0
        end_time = 0

        for pkg in source:
            curr_start = to_timestamp(source[pkg]['start'])
            curr_end = to_timestamp(source[pkg]['end'])
            if start_time == 0 or start_time > curr_start:
                start_time = curr_start
            if end_time == 0 or end_time < curr_end:
                end_time = curr_end

        return start_time, end_time

    def parse_report_json_file(check_dir):
        """Get data from report.json generated by gbs itself"""

        report_data = {'total': 0, 'pass': 0, 'fail': 0, 'dep_err': 0, 'exp_err': 0}

        if check_dir is None or check_dir == '':
            return report_data

        if not check_dir.endswith('/'):
            check_dir = '{}/'.format(check_dir)
        check_dir = '/logs/'.join(check_dir.split('/logs/')[:-1])

        if os.path.isfile(os.path.join(check_dir, 'report.json')):
            # pylint: disable=W0703
            try:
                with open(os.path.join(check_dir, 'report.json'), 'r') as report_f:
                    report_j = json.load(report_f)
                    if report_j and 'summary' in report_j:
                        if 'packages_total' in report_j['summary']:
                            report_data['total'] = int(report_j['summary']['packages_total'])
                        if 'packages_succeeded' in report_j['summary']:
                            report_data['pass'] = int(report_j['summary']['packages_succeeded'])
                        if 'packages_build_error' in report_j['summary']:
                            report_data['fail'] = int(report_j['summary']['packages_build_error'])
                        if 'packages_expansion_error' in report_j['summary']:
                            report_data['dep_err'] = \
                                int(report_j['summary']['packages_expansion_error'])
                        if 'packages_export_error' in report_j['summary']:
                            report_data['exp_err'] = \
                                int(report_j['summary']['packages_export_error'])
            except Exception as err:
                console('Error for reading report json: {}'.format(repr(err)))

        return report_data

    report_data = parse_report_json_file(user_log_dir)

    build_start, build_end = get_first_end_time(build_time)
    ref_start, ref_end = get_first_end_time(ref_build_time)

    meta['BuildDetail']['Total'] = len(build_time)
    meta['BuildDetail']['StartTime'] = build_start
    meta['BuildDetail']['EndTime'] = build_end
    meta['BuildDetail']['RunTime'] = build_end - build_start

    if report_data['total'] > 0:
        meta['BuildDetail']['Total'] = report_data['total']
        meta['BuildDetail']['Pass'] = report_data['pass']
        meta['BuildDetail']['Fail'] = report_data['fail'] \
                                      + report_data['exp_err'] + report_data['dep_err']

    meta['ReferenceDetail']['Total'] = len(ref_build_time)
    meta['ReferenceDetail']['StartTime'] = ref_start
    meta['ReferenceDetail']['EndTime'] = ref_end
    meta['ReferenceDetail']['RunTime'] = ref_end - ref_start

    return meta


def reconstruct_new_format(sample_dir, cpu_file):
    """Re-construct new format"""

    # Resource Monitoring Data
    # pylint: disable=W0703
    try:
        monitor_inst = Monitoring()
        monitor_data = monitor_inst.query_cpu_usage(cpu_file)
        monitor_inst.cleanup_record(cpu_file)
        save_result(os.path.join(sample_dir, 'depends'), 'hw_resource.json', monitor_data)
    except Exception as err:
        console('{}'.format(repr(err)), verbose=True)

    shutil.move(os.path.join(sample_dir, 'depends'), \
                os.path.join(sample_dir, 'datasets', 'default'))

    # depends_out/ -> .sample_data/
    tmp_sample_dir = os.path.join(os.path.dirname(sample_dir), '.sample_data')
    shutil.rmtree(os.path.join(sample_dir, '.sample_data'), ignore_errors=True)
    os.rename(sample_dir, tmp_sample_dir)
    # bsr_fe/build/ -> depends_out/
    script_dir = os.path.dirname(os.path.realpath(__file__))
    frontend_dist_dir = os.path.join(os.path.dirname(os.path.dirname(script_dir)), \
                                     'bsr', 'web_dist')
    shutil.copytree(frontend_dist_dir, sample_dir)
    # shutil.rmtree(os.path.join(sample_dir, 'sample_data'))
    # .sample_data/ -> depends_out/sample_data/
    shutil.move(tmp_sample_dir, os.path.join(sample_dir, 'sample_data'))

    # Change distribution URL
    subprocess.call('cp -rf {}/* {}/'.format(frontend_dist_dir, sample_dir), shell=True)


def save_result(target_dir, filename, input_data, raw=False):
    """Save json data into file"""

    with open(os.path.join(target_dir, filename), 'w') as result_f:
        if raw is True:
            result_f.write(input_data)
        else:
            json.dump(input_data, result_f, default=json_datetime_serializer)


# pylint: disable=R0914
def save_logs(target_dir, source_dir):
    """Hard link log files"""

    if source_dir and target_dir:
        shutil.copytree(source_dir, os.path.join(target_dir, 'logs'))


def fetch_ordered_list_from_previous_report(profiling_ref, verbose=False):
    """Generate ordered list from profiling report"""

    build_time_data = None
    depends_link_data = None

    def read_json_data(path):
        """Load json data"""

        local_bt = None
        local_dl = None
        try:
            if os.path.isfile(os.path.join(path, 'buildtime.json')) \
                    and os.path.isfile(os.path.join(path, 'depends_link.json')):
                with open(os.path.join(path, 'buildtime.json'), 'r') as bt_file:
                    local_bt = json.load(bt_file)
                with open(os.path.join(path, 'depends_link.json'), 'r') as link_file:
                    local_dl = json.load(link_file)
            else:
                console('Fetch failed...', verbose=verbose)
        except ValueError as err:
            console('Fetch exception... {}'.format(repr(err)), verbose=verbose)

        return [local_bt, local_dl]

    url = profiling_ref
    if not url.endswith('/'):
        url = url + '/'

    if '/sample_data' not in url:
        url = url + 'sample_data/datasets/default/'

    if url.startswith('http'):
        console('Downloading build time json from the url... {}'.format(url), \
                verbose=verbose)
        work_dir = os.path.join(os.getcwd(), \
                                '.prev_logs_{}'.format(datetime.now().strftime('%Y%m%d%H%M%S')))
        os.makedirs(work_dir)

        with pushd(work_dir):
            ar_files = '-R index.htm* -A "buildtime.json" -A "depends_link.json" '
            options = 'wget -q -r -nH -np -l 10 --cut-dirs=100 '
            main_command = '{} {} {}/'.format(options, ar_files, url)

            subprocess.call('{}'.format(main_command), \
                            stdout=sys.stdout, stderr=sys.stderr, shell=True)

        build_time_data, depends_link_data = read_json_data(work_dir)
        shutil.rmtree(work_dir, ignore_errors=True)

    elif os.path.isdir(url):
        build_time_data, depends_link_data = read_json_data(url)

    ordered_list = []

    if build_time_data and depends_link_data:
        p_lv = {}
        package_names = depends_link_data.get('package_names')
        for index, link in enumerate(depends_link_data.get('links')):
            if link.get('links') > 0:
                p_lv[package_names[index]] = link.get('links')

        ordered_list = ['{}'.format(x) for x in sorted(p_lv, key=lambda k: p_lv[k], reverse=True)]

        if 'initrd' in ordered_list and 'btrfs-progs' in ordered_list:
            initrd_idx = ordered_list.index('initrd')
            last_idx = len(ordered_list) - 1
            ordered_list[initrd_idx] = ordered_list[-1]
            ordered_list[last_idx] = 'initrd'

    return ordered_list
