#!/usr/bin/env ngs
ns(global_inspect=inspect) {

	global init

	# WIP
	# Ngs Amazon Swiss army Knife
	# This is an experiment towards creating the shell UI.

	Timeline  # autoload TimelineStatus
	type PipelineExecution(HashLike)
	type PipelineActionExecution(HashLike)

	F init(pe:PipelineExecution, h:Hash) {
		super(pe, h)
		pe.startTime .= Time()
		pe.lastUpdateTime .= Time()
	}

	F init(pae:PipelineActionExecution, h:Hash) {
		super(pae, h)
		pae.startTime .= Time()
		pae.lastUpdateTime .= Time()
	}

	F watch() {
		log("Starting to watch AWS profile ${profile}")
		while true {
			inspect()
			sleep(30)
		}
	}

	F horizon() {
		seconds = ENV.get('HORIZON', '3600').Int()
		Time(Time().Int() - seconds)
	}

	F inspect() {
		log("Looking up stacks")
		stacks = AWS2::regions(%(aws cloudformation describe-stacks))
		log("Stacks found in regions: ${stacks._Region.sort().Stats()}")

		log("Listing regions with codepipeline service")
		pipelines_regions = ``aws ssm get-parameters-by-path --path /aws/service/global-infrastructure/services/codepipeline/regions``.Value
		pipelines_regions .= filter(AnyOf(AWS2::regions()))  # Intersection of regions we are in and where the service is available
		# log("Pipelines are supported in regions: ${pipelines_regions}")

		log("Looking up pipelines")
		pipelines = AWS2::regions(%(aws codepipeline list-pipelines), pipelines_regions)
		log("Pipelines found in regions: ${pipelines._Region.sort().Stats()}")

		# pipelines.pmap(4, inspect_pipeline)
		inspect_pipeline(pipelines[0])

		# TODO: AMIs creation
	}


	F extract_error(pae:PipelineActionExecution) pae.output.executionResult.externalExecutionSummary

	F extract_error(pae:PipelineActionExecution) {
		guard pae =~ {"input": {"actionTypeId": {"owner": "AWS", "category": "Deploy", "provider": "CloudFormation"}}}
		# Following changeset failed - no way to correlate stack events with the changeset
		echo(pae)
		"<<<TODO CloudFormation>>> ${pae.output.executionResult.externalExecutionSummary}"
	}

	global Timeline

	F Timeline(pae:PipelineActionExecution) {
		# pipelineExecutionId, actionExecutionId, pipelineVersion, stageName, actionName, startTime, lastUpdateTime, status (InProgress, Succeeded, Failed), input, output,

		s = TimelineStatus
		status_translation = {
			'InProgress': s::Running()
			'Succeeded': s::Succeeded()
			'Failed': s::Failed()
		}

		Timeline()::{
			a = pae.input.actionTypeId
			A.name = "Pipeline Action Execution ${pae.actionExecutionId} ${pae.stageName}->${pae.actionName} [${a.owner} ${a.category} ${a.provider}] (${pae.status})"
			A.time_start = pae.startTime
			A.time_last_update = pae.lastUpdateTime
			A.data = pae
			A.status = status_translation[pae.status]
			if A.status =~ Not(s::Running) {
				A.time_end = pae.lastUpdateTime
			}
			if A.status is s::Failed {
				A.error = extract_error(pae)
			}
		}
	}


	F Timeline(pe:PipelineExecution) {

		# pe.status: InProgress, Stopped, Stopping, Succeeded, Superseded, Failed - https://awscli.amazonaws.com/v2/documentation/api/latest/reference/codepipeline/list-pipeline-executions.html
		s = TimelineStatus
		status_translation = {
			'InProgress': s::Running()
			'Stopped': s::Cancelled()
			'Stopping': s::Stopping()
			'Succeeded': s::Succeeded()
			'Superseded': s::Cancelled()
			'Failed': s::Failed()
		}

		Timeline()::{
			A.name = "Pipeline Execution ${pe.pipelineExecutionId} (${pe.status})"
			A.time_start = pe.startTime
			A.time_last_update = pe.lastUpdateTime
			A.data = pe
			A.status = status_translation[pe.status]
			if A.status =~ Not(s::Running) {
				A.time_end = pe.lastUpdateTime
			}
			if A.status =~ AnyOf(s::Failed, s::Running) {
				# https://awscli.amazonaws.com/v2/documentation/api/latest/reference/codepipeline/list-action-executions.html
				# pipelineExecutionId, actionExecutionId, pipelineVersion, stageName, actionName, startTime, lastUpdateTime, status (InProgress, Succeeded, Failed), input, output,
				actionExecutionDetails = ``aws codepipeline list-action-executions --pipeline-name ${pe._Name} --filter "pipelineExecutionId=${pe.pipelineExecutionId}" --region ${pe._Region}``
				actionExecutionDetails .= map(PipelineActionExecution)
				actionExecutionDetails._Region = ConstIter(pe._Region)
				# echo(actionExecutionDetails.global_inspect())
				A.items = actionExecutionDetails.map(Timeline)
				A.sort()
			}
		}
	}

	# TODO: AWS types such as CodePipeline
	F inspect_pipeline(pipeline:Hash) {
		assert(pipeline, {'name': Str, 'version': Int, 'created': Str, 'updated': Str, '_Region': Str})

		# lastUpdateTime pipelineExecutionId sourceRevisions startTime status trigger _Region
		pipelineExecutionSummaries = ``aws codepipeline list-pipeline-executions --pipeline-name ${pipeline.name} --region ${pipeline._Region}``
		pipelineExecutionSummaries._Region = ConstIter(pipeline._Region)
		pipelineExecutionSummaries._Name = ConstIter(pipeline.name)
		pipelineExecutionSummaries .= map(PipelineExecution)

		pipelineExecutionSummaries.map(Timeline).filter(F(ti) ti.Time() > horizon()).Timeline()::{
			A.name="Pipeline ${pipeline.name}"
			A.time_start = horizon()
		}
	}

	F inspect_pipeline(name:Str) {
		``aws codepipeline list-pipelines``.the_one({'name': name}).set(_Region=`line: aws configure get region`).inspect_pipeline()
	}

}