package recovery

import (
	"github.com/rancher/os/config"
	"github.com/rancher/os/pkg/compose"
	"github.com/rancher/os/pkg/init/docker"
	"github.com/rancher/os/pkg/log"
	"github.com/rancher/os/pkg/netconf"
	"github.com/rancher/os/pkg/sysinit"

	composeConfig "github.com/docker/libcompose/config"
	"github.com/docker/libcompose/yaml"
)

var (
	// TODO: move this into the os-config file so it can be customised.
	recoveryDockerService = composeConfig.ServiceConfigV1{
		Image: config.OsBase,
		Command: yaml.Command{
			"ros",
			"recovery-init",
		},
		Labels: map[string]string{
			config.DetachLabel: "false",
			config.ScopeLabel:  "system",
		},
		LogDriver:  "json-file",
		Net:        "host",
		Uts:        "host",
		Pid:        "host",
		Ipc:        "host",
		Privileged: true,
		Volumes: []string{
			"/dev:/host/dev",
			"/etc/ssl/certs/ca-certificates.crt:/etc/ssl/certs/ca-certificates.crt.rancher",
			"/lib/modules:/lib/modules",
			"/lib/firmware:/lib/firmware",
			"/usr/bin/ros:/usr/bin/ros:ro",
			"/usr/bin/ros:/usr/bin/cloud-init-save",
			"/usr/bin/ros:/usr/bin/respawn:ro",
			"/usr/share/ros:/usr/share/ros:ro",
			"/var/lib/rancher:/var/lib/rancher",
			"/var/lib/rancher/conf:/var/lib/rancher/conf",
			"/var/run:/var/run",
		},
	}
)

func LoadRecoveryConsole(cfg *config.CloudConfig) (*config.CloudConfig, error) {
	if cfg.Rancher.Recovery {
		Recovery(nil)
	}
	return cfg, nil
}

func Recovery(initFailure error) {
	if initFailure != nil {
		log.Errorf("RancherOS has failed to boot: %v", initFailure)
	}
	log.Info("Launching recovery console")

	var recoveryConfig config.CloudConfig
	recoveryConfig.Rancher.Defaults = config.Defaults{
		Network: netconf.NetworkConfig{
			DNS: netconf.DNSConfig{
				Nameservers: []string{
					"8.8.8.8",
					"8.8.4.4",
				},
			},
		},
	}
	recoveryConfig.Rancher.BootstrapDocker = config.DockerConfig{
		EngineOpts: config.EngineOpts{
			Bridge:        "none",
			StorageDriver: "overlay2",
			Restart:       &[]bool{false}[0],
			Graph:         "/var/lib/recovery-docker",
			Group:         "root",
			Host:          []string{"unix:///var/run/system-docker.sock"},
			UserlandProxy: &[]bool{false}[0],
		},
	}

	_, err := docker.Start(&recoveryConfig)
	if err != nil {
		log.Fatal(err)
	}

	_, err = config.ChainCfgFuncs(&recoveryConfig,
		[]config.CfgFuncData{
			{"loadSystemImages", sysinit.LoadBootstrapImages},
			{"recovery console", recoveryServices},
		})
	if err != nil {
		log.Fatal(err)
	}
}

func recoveryServices(cfg *config.CloudConfig) (*config.CloudConfig, error) {
	_, err := compose.RunServiceSet("recovery", cfg, map[string]*composeConfig.ServiceConfigV1{
		"recovery": &recoveryDockerService,
	})
	return nil, err
}
