# Copyright (c) 2023, JINGROW
# For license information, please see license.txt

import jingrow
from jingrow.model.page import Page
from jingrow.model.naming import append_number_if_name_exists

from jcloud.agent import Agent
from jcloud.utils import log_error
from jcloud.utils.dns import _change_dns_record, create_dns_record


class CodeServer(Page):
	# begin: auto-generated types
	# This code is auto-generated. Do not modify anything in this block.

	from typing import TYPE_CHECKING

	if TYPE_CHECKING:
		from jingrow.types import DF

		bench: DF.Link
		cluster: DF.Link | None
		domain: DF.Link
		group: DF.Link | None
		password: DF.Password | None
		proxy_server: DF.Link
		server: DF.Link | None
		status: DF.Literal["Pending", "Running", "Stopped", "Broken", "Archived"]
		subdomain: DF.Data
		team: DF.Link | None
	# end: auto-generated types

	def autoname(self):
		self.name = self.subdomain + "." + self.domain

	def validate(self):
		if not jingrow.get_value("Bench", self.bench, "is_code_server_enabled"):
			jingrow.throw(f"Code Server not enabled for the selected Bench {self.bench}")

		if self.has_value_changed("subdomain"):
			if jingrow.db.exists("Code Server", self.name):
				jingrow.throw(
					f"Code Server {self.name} already exists please choose a different name"
				)
			if jingrow.db.exists(
				"Code Server", {"bench": self.bench, "status": ("!=", "Archived")}
			):
				jingrow.throw(
					"Code Server already exists for selected bench choose a different bench"
				)
		if not self.proxy_server and self.has_value_changed("server"):
			self.proxy_server = jingrow.db.get_value("Server", self.server, "proxy_server")

	def after_insert(self):
		self.setup()

	@jingrow.whitelist()
	def setup(self):
		try:
			create_dns_record(pg=self, record_name=self.name)
			agent = Agent(self.proxy_server, server_type="Proxy Server")
			agent.new_upstream_file(server=self.server, code_server=self.name)

			self.password = jingrow.generate_hash(length=40)
			agent = Agent(self.server, server_type="Server")
			agent.setup_code_server(self.bench, self.name, self.password)
			self.save(ignore_permissions=True)
		except Exception as e:
			log_error(title="Setup Code Server Failed", data=e)

	@jingrow.whitelist()
	def stop(self):
		try:
			self.status = "Pending"
			agent = Agent(self.server, server_type="Server")
			agent.stop_code_server(self.bench, self.name)
		except Exception as e:
			log_error(title="Stop Code Server Failed", data=e)

	@jingrow.whitelist()
	def start(self):
		try:
			self.status = "Pending"
			agent = Agent(self.server, server_type="Server")
			self.password = jingrow.generate_hash(length=40)
			agent.start_code_server(self.bench, self.name, self.password)
			self.save(ignore_permissions=True)
		except Exception as e:
			log_error(title="Start Code Server Failed", data=e)

	@jingrow.whitelist()
	def archive(self):
		try:
			self.status = "Pending"
			_change_dns_record(
				method="DELETE",
				domain=jingrow.get_pg("Root Domain", self.domain),
				proxy_server=self.proxy_server,
				record_name=self.name,
			)
			agent = Agent(self.proxy_server, server_type="Proxy Server")
			agent.remove_upstream_file(server=self.server, code_server=self.name)

			agent = Agent(self.server, server_type="Server")
			agent.archive_code_server(self.bench, self.name)
			self.save(ignore_permissions=True)
		except Exception as e:
			log_error(title="Archive Code Server Failed", data=e)


def process_new_code_server_job_update(job):
	jingrow.db.get_value("Code Server", job.code_server, "status", for_update=True)

	other_job_type = {
		"Add Code Server to Upstream": "Setup Code Server",
		"Setup Code Server": "Add Code Server to Upstream",
	}[job.job_type]

	first = job.status
	second = jingrow.get_value(
		"Agent Job",
		{"job_type": other_job_type, "code_server": job.code_server},
		"status",
		for_update=True,
	)

	if "Success" == first == second:
		updated_status = "Running"
	elif "Failure" in (first, second):
		updated_status = "Broken"
	else:
		updated_status = "Pending"

	jingrow.db.set_value("Code Server", job.code_server, "status", updated_status)


def process_start_code_server_job_update(job):
	if job.status == "Success":
		jingrow.db.set_value("Code Server", job.code_server, "status", "Running")


def process_stop_code_server_job_update(job):
	if job.status == "Success":
		jingrow.db.set_value("Code Server", job.code_server, "status", "Stopped")


def process_archive_code_server_job_update(job):
	jingrow.db.get_value("Code Server", job.code_server, "status", for_update=True)

	other_job_type = {
		"Remove Code Server from Upstream": "Archive Code Server",
		"Archive Code Server": "Remove Code Server from Upstream",
	}[job.job_type]

	first = job.status
	second = jingrow.get_value(
		"Agent Job",
		{"job_type": other_job_type, "code_server": job.code_server},
		"status",
		for_update=True,
	)

	if "Success" == first == second:
		updated_status = "Archived"
	elif "Failure" in (first, second):
		updated_status = "Broken"
	else:
		updated_status = "Pending"

	jingrow.db.set_value("Code Server", job.code_server, "status", updated_status)
	if updated_status == "Archived":
		release_name(job.code_server)


def release_name(name):
	if ".archived" in name:
		return
	new_name = f"{name}.archived"
	new_name = append_number_if_name_exists("Code Server", new_name, separator=".")
	jingrow.rename_pg("Code Server", name, new_name)
