# Copyright (c) 2025, JINGROW and contributors
# For license information, please see license.txt

import jingrow
from datetime import datetime, timedelta
from random import randint
from croniter import CroniterBadCronError, croniter
from jingrow.model.page import Page
from jingrow.utils import get_datetime, now_datetime


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

		create_log: DF.Check
		cron_format: DF.Data | None
		frequency: DF.Literal["All", "Hourly", "Hourly Long", "Daily", "Daily Long", "Weekly", "Weekly Long", "Monthly", "Monthly Long", "Cron", "Yearly", "Annual"]
		last_execution: DF.Datetime | None
		method: DF.Data
		scheduler_event: DF.Link | None
		server_script: DF.Link | None
		stopped: DF.Check
	# end: auto-generated types

	@property
	def next_execution(self):
		"""计算下次执行时间 - 完全对齐 Scheduled Job Type 实现"""
		return self.get_next_execution()

	def get_next_execution(self):
		"""获取下次执行时间 - 完全对齐 Scheduled Job Type 的 get_next_execution 方法"""
		CRON_MAP = {
			"Yearly": "0 0 1 1 *",
			"Annual": "0 0 1 1 *",
			"Monthly": "0 0 1 * *",
			"Monthly Long": "0 0 1 * *",
			"Weekly": "0 0 * * 0",
			"Weekly Long": "0 0 * * 0",
			"Daily": "0 0 * * *",
			"Daily Long": "0 0 * * *",
			"Hourly": "0 * * * *",
			"Hourly Long": "0 * * * *",
			"All": f"*/{(jingrow.get_conf().scheduler_interval or 240) // 60} * * * *",
		}

		if not self.cron_format:
			self.cron_format = CRON_MAP.get(self.frequency)

		# If this is a cold start then last_execution will not be set.
		# Creation is set as fallback because if very old fallback is set job might trigger
		# immediately, even when it's meant to be daily.
		# A dynamic fallback like current time might miss the scheduler interval and job will never start.
		last_execution = get_datetime(self.last_execution or self.creation)
		next_execution = croniter(self.cron_format, last_execution).get_next(datetime)

		jitter = 0
		if "Long" in self.frequency:
			jitter = randint(1, 600)
		return next_execution + timedelta(seconds=jitter)
