use crate::{unwrap, Builder, MergeRequestHandler, Scheduler, Worker};
use rusty_yaml::Yaml;
use std::fmt::{Display, Error, Formatter};
use std::process::exit;
pub struct MasterConfig {
    title: String,     title_url: String,
    git_repo: String,
    webserver_ip: String,
    poll_interval: String,
    merge_request_handler: MergeRequestHandler,
    builders: Vec<Builder>,
    schedulers: Vec<Scheduler>,
    workers: Vec<Worker>,
}
impl MasterConfig {
    fn new(
        title: String,
        title_url: String,
        git_repo: String,
        webserver_ip: String,
        poll_interval: String,
        merge_request_handler: MergeRequestHandler,
        builders: Vec<Builder>,
        schedulers: Vec<Scheduler>,
        workers: Vec<Worker>,
    ) -> Self {
        Self {
            title,
            title_url,
            git_repo,
            webserver_ip,
            poll_interval,
            merge_request_handler,
            builders,
            schedulers,
            workers,
        }
    }
}
impl From<Yaml> for MasterConfig {
    fn from(yaml: Yaml) -> Self {
                for section in [
            "master",
            "workers",
            "builders",
            "schedulers",
            "merge-request-handler",
        ]
        .iter()
        {
            if !yaml.has_section(section) {
                error!("There was an error creating the master configuration file: '{}' section was not declared", section);
                exit(1);
            }
        }
                let master = yaml.get_section("master").unwrap();
                for section in [
            "title",
            "title-url",
            "repo",
            "webserver-ip",
            "poll-interval",
        ]
        .iter()
        {
            if !master.has_section(section) {
                error!("There was an error creating the master configuration file: The '{}' section is not specified for master", section);
                exit(1);
            }
        }
        let merge_request_handler =
            MergeRequestHandler::from(yaml.get_section("merge-request-handler").unwrap());
                                let mut schedulers = vec![];
        for scheduler in yaml.get_section("schedulers").unwrap() {
            schedulers.push(Scheduler::from(scheduler));
        }
                        let mut builders = vec![];
        for builder in yaml.get_section("builders").unwrap() {
            builders.push(Builder::from(builder));
        }
                        let mut workers = vec![];
        for worker in yaml.get_section("workers").unwrap() {
            workers.push(Worker::from(worker));
        }
                let title = unwrap(&master, "title");
        let title_url = unwrap(&master, "title-url");
        let git_repo = unwrap(&master, "repo");
        let webserver_ip = unwrap(&master, "webserver-ip");
        let poll_interval = unwrap(&master, "poll-interval");
                Self::new(
            title,
            title_url,
            git_repo,
            webserver_ip,
            poll_interval,
            merge_request_handler,
            builders,
            schedulers,
            workers,
        )
    }
}
impl Display for MasterConfig {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        write!(
            f,
            r#"
# -*- python -*-
# ex: set filetype=python:
import re
import json
import requests as req
from dateutil.parser import parse as dateparse
from buildbot.plugins import *
from buildbot.www.hooks.github import GitHubEventHandler
# This is a sample buildmaster config file. It must be installed as
# 'master.cfg' in your buildmaster's base directory.
# This is the dictionary that the buildmaster pays attention to. We also use
# a shorter alias to save typing.
c = BuildmasterConfig = {{}}
####### WORKERS
# The 'workers' list defines the set of recognized workers. Each element is
# a Worker object, specifying a unique worker name and password.  The same
# worker name and password must be configured on the worker.
c['workers'] = [{worker_info}]
c['protocols'] = {{'pb': {{'port': 9989}}}}
c['www'] = dict(port=8010,
                plugins=dict(waterfall_view={{}}, console_view={{}}, grid_view={{}}))
c['change_source'] = []
c['services'] = []
{merge_request_handler}
c['change_source'].append(changes.GitPoller(
        "{git_repo}",
        workdir='gitpoller-workdir', branches=True, # poll all branches
        pollInterval={poll_interval}))
c['schedulers'] = []
c['builders'] = []
{schedulers}
{builders}
c['title'] = "{title}"
c['titleURL'] = "{title_url}"
c['buildbotURL'] = "http://{webserver_ip}:8010/"
c['db'] = {{
    # This specifies what database buildbot uses to store its state.  You can leave
    # this at its default for all but the largest installations.
    'db_url' : "sqlite:///state.sqlite",
}}
        "#,
            title = self.title,
            title_url = self.title_url,
            webserver_ip = self.webserver_ip,
            git_repo = self.git_repo,
            merge_request_handler = self.merge_request_handler,
            worker_info = self
                .workers
                .iter()
                .map(|w| {
                    format!(
                        "worker.Worker(\"{}\", \"{}\")",
                        w.get_name(),
                        w.get_password()
                    )
                })
                .collect::<Vec<String>>()
                .join(", "),
            poll_interval = self.poll_interval,
            schedulers = self
                .schedulers
                .iter()
                .map(|s| s.to_string())
                .collect::<Vec<String>>()
                .join("\n\n"),
            builders = self
                .builders
                .iter()
                .map(|b| b.to_string())
                .collect::<Vec<String>>()
                .join("\n\n"),
        )
    }
}