/**
 * PKWT Notification Scheduler
 * Automated scheduler untuk generate notifikasi PKWT yang akan berakhir
 *
 * Usage:
 * - Import dan panggil startScheduler() di app.js
 * - Atau jalankan secara manual dengan runPKWTNotificationCheck()
 *
 * Configuration:
 * - Konfigurasi dapat diatur per company melalui CompanySetting:
 *   - pkwt_scheduler_enabled: boolean (default: true)
 *   - pkwt_scheduler_interval_hours: number (default: 24)
 *   - pkwt_scheduler_days_before_expiration: number (default: 30)
 */

const notificationService = require("./notification.service");
const dbSAPPS = require("../../helpers/db");

let schedulerInterval = null;
let isRunning = false;
let isExecuting = false;

/**
 * Get PKWT scheduler configuration for a company
 * @param {Number} company_id - Company ID
 * @returns {Promise<Object>} - Scheduler configuration object
 */
async function getCompanySchedulerConfig(company_id) {
	try {
		const settings = await dbSAPPS.CompanySetting.findAll({
			where: {
				company_id: company_id,
				key: {
					[dbSAPPS.Sequelize.Op.in]: ["pkwt_scheduler_enabled", "pkwt_scheduler_interval_hours", "pkwt_scheduler_days_before_expiration"],
				},
			},
		});

		const config = {
			enabled: true, // Default: enabled
			intervalHours: 24, // Default: 24 hours (daily)
			daysBeforeExpiration: 30, // Default: 30 days
		};

		settings.forEach((setting) => {
			try {
				if (setting.key === "pkwt_scheduler_enabled") {
					// Handle boolean values (can be "true"/"false" string or boolean)
					const value = setting.value;
					if (typeof value === "string") {
						config.enabled = value.toLowerCase() === "true" || value === "1";
					} else {
						config.enabled = Boolean(value);
					}
				} else if (setting.key === "pkwt_scheduler_interval_hours") {
					const parsed = parseInt(setting.value, 10);
					if (!isNaN(parsed) && parsed > 0) {
						config.intervalHours = parsed;
					}
				} else if (setting.key === "pkwt_scheduler_days_before_expiration") {
					const parsed = parseInt(setting.value, 10);
					if (!isNaN(parsed) && parsed > 0) {
						config.daysBeforeExpiration = parsed;
					}
				}
			} catch (error) {
				console.warn(`Failed to parse scheduler setting ${setting.key} for company ${company_id}:`, error);
			}
		});

		return config;
	} catch (error) {
		console.error(`Error getting scheduler config for company ${company_id}:`, error);
		// Return default config on error
		return {
			enabled: true,
			intervalHours: 24,
			daysBeforeExpiration: 30,
		};
	}
}

/**
 * Get all companies with PKWT scheduler enabled
 * @returns {Promise<Array>} - Array of company IDs with scheduler enabled
 */
async function getEnabledCompanies() {
	try {
		const enabledSettings = await dbSAPPS.CompanySetting.findAll({
			where: {
				key: "pkwt_scheduler_enabled",
			},
			attributes: ["company_id", "value"],
		});

		const enabledCompanyIds = [];
		const disabledCompanyIds = new Set();

		enabledSettings.forEach((setting) => {
			try {
				const value = setting.value;
				let isEnabled = true; // Default: enabled if not set

				if (typeof value === "string") {
					isEnabled = value.toLowerCase() === "true" || value === "1";
				} else {
					isEnabled = Boolean(value);
				}

				if (isEnabled) {
					enabledCompanyIds.push(setting.company_id);
				} else {
					disabledCompanyIds.add(setting.company_id);
				}
			} catch (error) {
				console.warn(`Failed to parse scheduler enabled setting for company ${setting.company_id}:`, error);
				// Default to enabled if parsing fails
				enabledCompanyIds.push(setting.company_id);
			}
		});

		// Get all companies and filter out disabled ones
		const allCompanies = await dbSAPPS.Company.findAll({
			where: {
				enabled: true,
			},
			attributes: ["id"],
		});

		// If no settings exist, all enabled companies are included
		if (enabledSettings.length === 0) {
			return allCompanies.map((c) => c.id);
		}

		// Return companies that are either explicitly enabled or not in disabled list
		const result = allCompanies
			.map((c) => c.id)
			.filter((id) => {
				// If company has explicit setting, use it
				if (enabledCompanyIds.includes(id)) {
					return true;
				}
				if (disabledCompanyIds.has(id)) {
					return false;
				}
				// If no setting exists, default to enabled
				return true;
			});

		return result;
	} catch (error) {
		console.error("Error getting enabled companies:", error);
		// Return empty array on error to prevent scheduler from running
		return [];
	}
}

/**
 * Run PKWT notification check manually
 * @param {Object} options - Scheduler options
 * @param {Number} options.daysBeforeExpiration - Days before expiration to notify (default: 30, or from company settings)
 * @param {Array} options.companiesId - Optional: filter by company IDs (if not provided, uses enabled companies)
 * @param {Number} options.modified_by - User ID (default: 1)
 * @param {Number} options.owner - Owner ID (default: 1)
 * @param {Boolean} options.useCompanySettings - Use company-specific settings (default: true)
 * @returns {Promise<Object>} - Result object
 */
async function runPKWTNotificationCheck(options = {}) {
	try {
		console.log(`[PKWT Scheduler] Running PKWT notification check at ${new Date().toISOString()}`);

		let companiesId = options.companiesId || null;
		let daysBeforeExpiration = options.daysBeforeExpiration || 30;

		// If companiesId not provided and useCompanySettings is true, get enabled companies
		if (!companiesId && options.useCompanySettings !== false) {
			companiesId = await getEnabledCompanies();
			if (companiesId.length === 0) {
				console.log("[PKWT Scheduler] No companies with scheduler enabled, skipping check");
				return {
					success: true,
					message: "No companies with scheduler enabled",
					notificationsCreated: 0,
					employeesChecked: 0,
				};
			}
			console.log(`[PKWT Scheduler] Found ${companiesId.length} companies with scheduler enabled`);
		}

		// If useCompanySettings is true, we'll use per-company settings in generatePKWTNotifications
		// Otherwise, use the provided daysBeforeExpiration
		const params = {
			daysBeforeExpiration: daysBeforeExpiration,
			companiesId: companiesId,
			modified_by: options.modified_by || 1,
			owner: options.owner || 1,
			doctype_id: options.doctype_id || null,
			useCompanySettings: options.useCompanySettings !== false, // Default: true
		};

		const result = await notificationService.generatePKWTNotifications(params);

		if (result.success) {
			console.log(`[PKWT Scheduler] Success: Created ${result.notificationsCreated} notifications, checked ${result.employeesChecked} employees`);
			if (result.errors && result.errors.length > 0) {
				console.warn(`[PKWT Scheduler] Warnings: ${result.errors.length} errors occurred`);
				result.errors.forEach((err) => {
					console.warn(`  - Employee ${err.employee_id} (${err.employee_name}): ${err.error}`);
				});
			}
		} else {
			console.error(`[PKWT Scheduler] Error: ${result.message}`);
		}

		return result;
	} catch (error) {
		console.error("[PKWT Scheduler] Fatal error:", error);
		return {
			success: false,
			message: error.message || "Failed to run PKWT notification check",
		};
	}
}

/**
 * Start scheduler to run PKWT notification check periodically
 * @param {Object} options - Scheduler options
 * @param {Number} options.intervalHours - Interval in hours (default: 24, runs daily, or from company settings)
 * @param {Number} options.daysBeforeExpiration - Days before expiration to notify (default: 30, or from company settings)
 * @param {Array} options.companiesId - Optional: filter by company IDs (if not provided, uses enabled companies)
 * @param {Number} options.modified_by - User ID (default: 1)
 * @param {Number} options.owner - Owner ID (default: 1)
 * @param {Number} options.doctype_id - DocType ID for PKWT notifications
 * @param {Boolean} options.runImmediately - Run immediately on start (default: true)
 * @param {Boolean} options.useCompanySettings - Use company-specific settings (default: true)
 * @returns {Object} - Scheduler status
 */
function startScheduler(options = {}) {
	if (isRunning) {
		console.warn("[PKWT Scheduler] Scheduler is already running");
		return {
			success: false,
			message: "Scheduler is already running",
		};
	}

	const intervalHours = options.intervalHours || 24; // Default: daily
	const intervalMs = intervalHours * 60 * 60 * 1000; // Convert to milliseconds

	console.log(`[PKWT Scheduler] Starting scheduler with ${intervalHours} hour interval`);
	console.log(`[PKWT Scheduler] Using company-specific settings: ${options.useCompanySettings !== false}`);

	// Run immediately if requested (default: true)
	if (options.runImmediately !== false) {
		if (!isExecuting) {
			isExecuting = true;
			runPKWTNotificationCheck({
				...options,
				useCompanySettings: options.useCompanySettings !== false,
			})
				.catch((err) => {
					console.error("[PKWT Scheduler] Error in initial run:", err);
				})
				.finally(() => {
					isExecuting = false;
				});
		} else {
			console.log("[PKWT Scheduler] Initial run skipped (previous run still in progress)");
		}
	}

	// Schedule periodic runs
	schedulerInterval = setInterval(async () => {
		if (isExecuting) {
			console.log("[PKWT Scheduler] Previous run still in progress, skipping");
			return;
		}
		isExecuting = true;
		try {
			await runPKWTNotificationCheck({
				...options,
				useCompanySettings: options.useCompanySettings !== false,
			});
		} catch (err) {
			console.error("[PKWT Scheduler] Error in scheduled run:", err);
		} finally {
			isExecuting = false;
		}
	}, intervalMs);

	isRunning = true;

	console.log(`[PKWT Scheduler] Scheduler started successfully. Next run in ${intervalHours} hours`);

	return {
		success: true,
		message: `Scheduler started with ${intervalHours} hour interval`,
		intervalHours: intervalHours,
		isRunning: true,
	};
}

/**
 * Stop the scheduler
 * @returns {Object} - Stop status
 */
function stopScheduler() {
	if (!isRunning) {
		return {
			success: false,
			message: "Scheduler is not running",
		};
	}

	if (schedulerInterval) {
		clearInterval(schedulerInterval);
		schedulerInterval = null;
	}

	isRunning = false;
	console.log("[PKWT Scheduler] Scheduler stopped");

	return {
		success: true,
		message: "Scheduler stopped successfully",
		isRunning: false,
	};
}

/**
 * Get scheduler status
 * @returns {Object} - Scheduler status
 */
function getSchedulerStatus() {
	return {
		isRunning: isRunning,
		hasInterval: schedulerInterval !== null,
	};
}

module.exports = {
	runPKWTNotificationCheck,
	startScheduler,
	stopScheduler,
	getSchedulerStatus,
	getCompanySchedulerConfig,
	getEnabledCompanies,
};
