#!/usr/bin/env python3

import requests
from typing import Optional, List, Dict
import json
import os
from urllib.parse import urljoin
import datetime
import numpy
import csv

class Build:

    def __init__(self, job_name: str, build_dict: Dict):
        self.job_name = job_name
        self.number = build_dict['number']
        self.result = build_dict['result']
        self.start_time = datetime.datetime.fromtimestamp(build_dict['timestamp']/1000)
        self.duration = datetime.timedelta(milliseconds=build_dict['duration'])

    @property
    def hour(self) -> datetime.datetime:
        return datetime.datetime(
            year=self.start_time.year,
            month=self.start_time.month,
            day=self.start_time.day,
            hour=self.start_time.hour,
        )

    @property
    def day(self) -> datetime.datetime:
        return datetime.datetime(
            year=self.start_time.year,
            month=self.start_time.month,
            day=self.start_time.day,
        )


class JenkinsStatsReader:

    _JENKINS_DAT_FILE = 'tmp/jenkins.json'

    def __init__(self):
        self.username = None  # type: Optional[str]
        self.password = None  # type: Optional[str]
        self.jenkins_url = None  # type: Optional[str]
        self.jobs = []  # type: List[str]
        self.builds = {}  # type: Dict[str, List[Build]]
        self._read_config()
        self._session = requests.session()
        self._session.auth = (self.username, self.password)

    def _read_config(self, credential_path='~/.llvm-premerge-checks/jenkins-creds.json'):
        with open(os.path.expanduser(credential_path)) as credential_file:
            config = json.load(credential_file)
        self.username = config['username']
        self.password = config['password']
        self.jenkins_url = config['jenkins_url']

    @property
    def job_names(self) -> List[str]:
        return self.builds.keys()

    def get_data(self):
        if not os.path.isfile(self._JENKINS_DAT_FILE):
            self.fetch_data()
        self.parse_data()
        self.create_statistics('hour')
        self.create_statistics('day')

    def fetch_data(self):
        response = self._session.get(
            urljoin(self.jenkins_url, 'api/json?tree=jobs[name,url,allBuilds[number,result,duration,url,timestamp]]'))
        with open(self._JENKINS_DAT_FILE, 'w') as jenkins_data_file:
            json.dump(response.json(), jenkins_data_file)

    def parse_data(self):
        with open(self._JENKINS_DAT_FILE) as jenkins_data_file:
            build_data = json.load(jenkins_data_file)
        for job in build_data['jobs']:
            job_name = job['name']
            self.builds[job_name] = [Build(job_name, b) for b in job['allBuilds']]
            print('{} has {} builds'.format(job_name, len(self.builds[job_name])))

    def create_statistics(self, group_by: str):
        # only look at Phab
        for job_name, builds in self.builds.items():
            print('Writing data for {}'.format(job_name))
            # TODO: add success/failure rates
            fieldnames = ['date', '# builds', 'median duration', 'p90 duration', 'p95 duration', 'max duration']
            csv_file = open('tmp/jenkins_{}_{}.csv'.format(job_name, group_by), 'w')
            writer = csv.DictWriter(csv_file, fieldnames=fieldnames, dialect=csv.excel)
            writer.writeheader()
            build_hist = {}
            for build in builds:
                build_hist.setdefault(getattr(build, group_by), []).append(build)

            for key in sorted(build_hist.keys()):
                builds = build_hist[key]   # type: List[Build]
                durations = numpy.array([b.duration.seconds for b in builds])
                writer.writerow({
                    'date': key,
                    '# builds': len(builds),
                    'median duration': numpy.median(durations)/60,
                    'p90 duration':  numpy.percentile(durations, 90)/60,
                    'p95 duration': numpy.percentile(durations, 95)/60,
                    'max duration': numpy.max(durations)/60,
                })


if __name__ == '__main__':
    jsr = JenkinsStatsReader()
    jsr.get_data()