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

import os
import shutil
import subprocess
from pathlib import Path

import jingrow
from jingrow.model.page import Page
from jingrow.modules.export_file import export_pg
from jingrow.query_builder.functions import Max


class PackageRelease(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

		major: DF.Int
		minor: DF.Int
		package: DF.Link
		patch: DF.Int
		path: DF.SmallText | None
		publish: DF.Check
		release_notes: DF.MarkdownEditor | None

	# end: auto-generated types
	def set_version(self):
		"""设置版本号，如果未设置则自动计算下一个版本"""
		pagetype = jingrow.qb.PageType("Package Release")
		
		# 一次查询获取所有版本信息
		result = (
			jingrow.qb.from_(pagetype)
			.where(pagetype.package == self.package)
			.select(Max(pagetype.major), Max(pagetype.minor), Max(pagetype.patch))
			.run()[0]
		)
		
		max_major, max_minor, max_patch = result
		
		# 安全转换为整数，处理 None 和字符串情况
		def safe_int(value, default=0):
			try:
				return int(value) if value is not None else default
			except (TypeError, ValueError):
				return default
		
		if not self.major:
			self.major = safe_int(max_major)
		
		if not self.minor:
			self.minor = safe_int(max_minor)
		
		if not self.patch:
			self.patch = safe_int(max_patch) + 1

	def autoname(self):
		self.set_version()
		self.name = "{}-{}.{}.{}".format(
			jingrow.db.get_value("Package", self.package, "package_name"), self.major, self.minor, self.patch
		)

	def validate(self):
		package = jingrow.get_pg("Package", self.package)
		package_path = Path(jingrow.get_site_path("packages", package.package_name))
		if not package_path.resolve().is_relative_to(Path(jingrow.get_site_path()).resolve()):
			jingrow.throw("Invalid package path: " + package_path.as_posix())

		if self.publish:
			self.export_files(package)

	def export_files(self, package):
		"""Export all the documents in this package to site/packages folder"""

		self.export_modules()
		self.export_package_files(package)
		self.make_tarfile(package)

	def export_modules(self):
		for m in jingrow.get_all("Module Def", dict(package=self.package)):
			module = jingrow.get_pg("Module Def", m.name)
			for l in module.meta.links:
				if l.link_pagetype == "Module Def":
					continue
				# all documents of the type in the module
				for d in jingrow.get_all(l.link_pagetype, dict(module=m.name)):
					export_pg(jingrow.get_pg(l.link_pagetype, d.name))

	def export_package_files(self, package):
		# ensure package directory exists
		package_dir = Path(jingrow.get_site_path("packages", package.package_name))
		package_dir.mkdir(parents=True, exist_ok=True)
		
		# write readme
		with open(package_dir / "README.md", "w") as readme:
			readme.write(str(package.readme or ""))

		# write license
		if package.license:
			with open(package_dir / "LICENSE.md", "w") as license:
				license.write(str(package.license or ""))

		# write package.json
		with open(package_dir / f"{package.package_name}.json", "w") as packagefile:
			packagefile.write(jingrow.as_json(package.as_dict(no_nulls=True)))

	def make_tarfile(self, package):
		# make tarfile
		filename = f"{self.name}.tar.gz"
		subprocess.check_output(
			["tar", "czf", filename, package.package_name], cwd=jingrow.get_site_path("packages")
		)

		# move file
		subprocess.check_output(
			["mv", jingrow.get_site_path("packages", filename), jingrow.get_site_path("public", "files")]
		)

		# make attachment
		file = jingrow.get_pg(
			dict(
				pagetype="File",
				file_url="/" + os.path.join("files", filename),
				attached_to_pagetype=self.pagetype,
				attached_to_name=self.name,
			)
		)

		# Set path to tarball
		self.path = file.file_url

		file.flags.ignore_duplicate_entry_error = True
		file.insert()

	def after_delete(self):
		"""Clean up related files after Package Release deletion"""
		if self.package:
			try:
				package = jingrow.get_pg("Package", self.package)
				if package:
					# Delete package directory
					package_dir = Path(jingrow.get_site_path("packages", package.package_name))
					if package_dir.exists():
						shutil.rmtree(package_dir)
					
					# Delete tar file
					if self.path:
						tar_file = Path(jingrow.get_site_path("public", self.path.lstrip("/")))
						if tar_file.exists():
							tar_file.unlink()
			except Exception as e:
				jingrow.log_error("Package Release cleanup error", str(e))
