# Copyright (c) 2022, Frappe and contributors
# For license information, please see license.txt

import jingrow
from frappe.model.document import Document

from press.runner import Ansible
from press.utils import log_error


class MalwareScan(Document):
	# 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 frappe.types import DF

		play: DF.Link | None
		server: DF.DynamicLink
		server_type: DF.Literal["Server", "Database Server", "Proxy Server"]
		status: DF.Literal["Pending", "Installed", "Not Installed", "Running", "Clean", "Infected", "Failure"]
	# end: auto-generated types

	def after_insert(self):
		self.check_clamav()

	def check_clamav(self):
		self.status = "Pending"
		self.save()
		frappe.db.commit()
		frappe.enqueue_pg(self.doctype, self.name, "_check_clamav", queue="default")

	def _check_clamav(self):
		try:
			server = frappe.get_pg(self.server_type, self.server)
			ansible = Ansible(
				playbook="pkg_exists.yml",
				server=server,
				user=server._ssh_user(),
				port=server._ssh_port(),
				variables={"pkg": "clamav"},
			)
			self.reload()
			self.play = ansible.play
			self.status = "Running"
			self.save()
			frappe.db.commit()
			play = ansible.run()
			if play.status == "Success":
				self.status = "Installed"
			else:
				self.status = "Not Installed"
		except Exception:
			log_error("ClamAV Install Exception", scan=self.as_dict())
			self.status = "Failure"
		self.save()

	@jingrow.whitelist()
	def start(self):
		self.status = "Pending"
		self.save()
		frappe.db.commit()
		frappe.enqueue_pg(self.doctype, self.name, "_start", queue="long", timeout=32000)

	def _start(self):
		try:
			server = frappe.get_pg(self.server_type, self.server)
			ansible = Ansible(
				playbook="malware_scan.yml",
				server=server,
				user=server._ssh_user(),
				port=server._ssh_port(),
			)
			self.reload()
			self.play = ansible.play
			self.status = "Running"
			self.save()
			frappe.db.commit()
			play = ansible.run()
			if play.status == "Success":
				self.succeed()
			else:
				self.fail()
		except Exception:
			log_error("Malware Scan Exception", scan=self.as_dict())
			self.fail()
		self.save()

	def succeed(self):
		output = frappe.db.get_value(
			"Ansible Task", {"task": "Scan home directory", "play": self.play}, "output"
		)
		if "Infected files:" in output:
			if "Infected files: 0" in output:
				self.status = "Clean"
			else:
				self.status = "Infected"
				self.send_infected_alert()
			return
		self.fail()

	def send_infected_alert(self):
		domain = frappe.get_value("Press Settings", "Press Settings", "domain")
		message = f"""
Malware Scan for *{self.server}* found malware, review.

[Malware Scan]({domain}{self.get_url()})
"""
		self.send_alert(message)

	def fail(self):
		self.status = "Failure"
		domain = frappe.get_value("Press Settings", "Press Settings", "domain")
		message = f"""
Malware Scan for *{self.server}* failed.

[Malware Scan]({domain}{self.get_url()})
"""
		self.send_alert(message)

	def send_alert(self, message):
		pass
