require("dotenv").config();
const axios = require("axios");

module.exports = {
	getAccounts,
	getOptionAccounts,
	importAll,
};

async function getAccounts(params) {
	try {
		// get
		const accounts = await axios.get(`${params.api_url}api/resource/Account`, {
			headers: {
				Authorization: `token ${params.api_key}:${params.api_secret}`,
				"Content-Type": "application/x-www-form-urlencoded, multipart/form-data",
				Accept: "application/json",
			},
			params: {
				fields: '["*"]',
				limit_start: "0",
				limit_page_length: "0",
				order_by: "modified DESC",
				debug: "true",
				// filters: '[["disabled","=",0]]',
			},
		});

		return {
			accounts: accounts.data.data || [],
			success: true,
			message: "Loaded successfully!",
		};
	} catch (error) {
		const errorMessage = error?.message || "Failed to load, please try again!";
		return {
			success: false,
			message: errorMessage,
		};
	}
}

async function getOptionAccounts(params) {
	try {
		// get
		const options = await axios.get(`${params.api_url}api/resource/Account`, {
			headers: {
				Authorization: `token ${params.api_key}:${params.api_secret}`,
				"Content-Type": "application/x-www-form-urlencoded, multipart/form-data",
				Accept: "application/json",
			},
			params: {
				fields: '["*"]',
				limit_start: "0",
				limit_page_length: "0",
				order_by: "modified DESC",
				debug: "true",
				filters: '[["disabled","=",0]]',
			},
		});

		return {
			options: options.data.data || [],
			success: true,
			message: "Loaded successfully!",
		};
	} catch (error) {
		const errorMessage = error?.message || "Failed to load, please try again!";
		return {
			success: false,
			message: errorMessage,
		};
	}
}

// Fungsi importAll disesuaikan dengan struktur kode contoh Anda.
// Ditambahkan: Cek company berdasarkan name untuk mengisi company_id.
// Ditambahkan: Replace owner dan modified_by dengan angka 4.
// Menggunakan Sequelize untuk transaksi, validasi existing, dan insert.
// Bangun hirarki berdasarkan account_number, identifikasi parents (is_group: true), sort berdasarkan account_number sampai buat seperti hirarki dari situ anda bisa mendahulukan semua parent terinsert dengan baik baru child nya di insert.
// Ditambahkan: Handle account yang tidak memiliki account_number (skip dari sorting/mapping, gunakan parent_account langsung jika ada).
// Ditambahkan: Handle root parent (jika parentAccountNumber sama dengan account_number sendiri, set parent_account = null).
// Ditambahkan: Jika parent tidak ditemukan untuk child, treat sebagai root dengan warning (bukan error).
// Ditambahkan: Jika account sudah ada berdasarkan name, cek perubahan field lain dan update jika perlu.

async function importAll(params) {
	const transaction = await dbSAPPS.sequelize.transaction();
	try {
		// Validasi input: pastikan params adalah array dan tidak kosong
		if (!Array.isArray(params) || params.length === 0) {
			throw new Error("Invalid input: params must be a non-empty array of account objects.");
		}

		// Validasi struktur setiap account, isi company_id, dan replace owner/modified_by
		for (let i = 0; i < params.length; i++) {
			const acc = params[i];
			if (!acc.name || !acc.account_name || !acc.company) {
				throw new Error(`Invalid account data at index ${i}: missing required fields (name, account_name, company).`);
			}

			// Cek company berdasarkan name
			const company = await dbSAPPS.Company.findOne({
				where: { name: acc.company },
			});
			if (!company) {
				throw new Error(`Company '${acc.company}' not found for account '${acc.name}'.`);
			}
			acc.company_id = company.id; // Isi company_id dengan ID dari company

			// Replace owner dan modified_by dengan angka 4
			acc.owner = 4;
			acc.modified_by = 4;
		}

		// Fungsi untuk menentukan parent berdasarkan account_number
		// Asumsi: Parent adalah account dengan account_number yang lebih pendek atau prefix dari child
		// Contoh: "1000.000" adalah parent dari "1100.000", "1110.000", dll.
		const getParentAccountNumber = (accountNumber) => {
			if (!accountNumber) return null;
			const parts = accountNumber.split(".");
			if (parts.length > 1) {
				parts.pop(); // Hapus bagian terakhir untuk dapat parent
				return parts.join(".") + ".000"; // Asumsi format .000 untuk parent
			}
			return null; // Root parent
		};

		// Bangun hirarki: Map account_number -> account object (hanya untuk yang punya account_number)
		const accountMap = new Map();
		const parents = [];
		const children = [];

		for (const acc of params) {
			if (acc.account_number) {
				accountMap.set(acc.account_number, acc);
			}
			if (acc.is_group === true || acc.is_group === 1) {
				parents.push(acc);
			} else {
				children.push(acc);
			}
		}

		// Sort parents berdasarkan account_number ascending untuk hirarki (root dulu)
		// Hanya sort yang punya account_number
		parents.sort((a, b) => {
			const aNum = a.account_number || "";
			const bNum = b.account_number || "";
			return aNum.localeCompare(bNum);
		});

		// Map untuk menyimpan account_number -> ID (hanya untuk yang punya account_number)
		const accountIdMap = new Map();
		const insertedIds = [];
		const updatedIds = [];

		// Fungsi helper untuk cek dan update jika ada perubahan
		const checkAndUpdate = async (acc, existing) => {
			// Bandingkan field-field utama (exclude id, created_at, dll.)
			const fieldsToCheck = [
				"account_name",
				"account_number",
				"is_group",
				"root_type",
				"report_type",
				"account_currency",
				"inter_company_account",
				"parent_account",
				"account_type",
				"tax_rate",
				"freeze_account",
				"balance_must_be",
				"lft",
				"rgt",
				"old_parent",
				"include_in_gross",
				"_user_tags",
				"_comments",
				"_assign",
				"_liked_by",
				"company_id",
				"owner",
				"modified_by",
			];
			let hasChanges = false;
			const updateData = {};

			for (const field of fieldsToCheck) {
				if (acc[field] !== existing[field]) {
					hasChanges = true;
					updateData[field] = acc[field];
				}
			}

			if (hasChanges) {
				await dbSAPPS.Account.update(updateData, {
					where: { id: existing.id },
					transaction,
				});
				console.log(`Updated account '${acc.name}' with changes.`);
				updatedIds.push(existing.id);
			}
			return existing.id;
		};

		// 1. Insert atau update semua parents dalam urutan hirarki
		for (const parent of parents) {
			// Tentukan parent_account berdasarkan account_number jika belum ada dan account_number ada
			let parentAccountNumber = parent.parent_account;
			if (!parentAccountNumber && parent.account_number) {
				parentAccountNumber = getParentAccountNumber(parent.account_number);
			}

			// Jika parentAccountNumber sama dengan account_number sendiri, ini adalah root parent
			if (parentAccountNumber === parent.account_number) {
				parent.parent_account = null; // Root parent
			} else if (parentAccountNumber && accountMap.has(parentAccountNumber)) {
				// Jika ada parent_account, pastikan parent-nya sudah ada di map
				const parentId = accountIdMap.get(parentAccountNumber);
				if (!parentId) {
					throw new Error(`Parent account '${parentAccountNumber}' not found for parent '${parent.name}'. Ensure hierarchy is correct.`);
				}
				parent.parent_account = parentId; // Update dengan ID
			} else if (parentAccountNumber && !accountMap.has(parentAccountNumber)) {
				// Jika parent_account adalah string tapi tidak ada di data, anggap sebagai root atau skip
				console.warn(`Parent account '${parentAccountNumber}' for '${parent.name}' not in data, treating as root.`);
				parent.parent_account = null;
			} else {
				parent.parent_account = null; // Root parent
			}

			// Cek existing berdasarkan name
			const existing = await dbSAPPS.Account.findOne({
				where: { name: parent.name },
				transaction,
			});
			if (existing) {
				// Cek dan update jika ada perubahan
				const id = await checkAndUpdate(parent, existing);
				if (parent.account_number) {
					accountIdMap.set(parent.account_number, id);
				}
			} else {
				// Save parent baru
				const account = await dbSAPPS.Account.create(parent, { transaction });
				if (parent.account_number) {
					accountIdMap.set(parent.account_number, account.id);
				}
				insertedIds.push(account.id);
			}
		}

		// 2. Insert atau update children dengan parent_account diisi ID berdasarkan account_number atau parent_account langsung
		for (const child of children) {
			// Cari parent_account berdasarkan account_number jika belum ada dan account_number ada
			let parentAccountNumber = child.parent_account;
			if (!parentAccountNumber && child.account_number) {
				parentAccountNumber = getParentAccountNumber(child.account_number);
			}

			// Cari ID parent dari map berdasarkan account_number
			let parentId = null;
			if (parentAccountNumber) {
				parentId = accountIdMap.get(parentAccountNumber);
				if (!parentId) {
					// Jika parent tidak ditemukan, treat sebagai root dengan warning
					console.warn(`Parent account '${parentAccountNumber}' not found for child '${child.name}', treating as root.`);
					parentId = null;
				}
			}

			// Update child.parent_account dengan ID
			child.parent_account = parentId;

			// Cek existing berdasarkan name
			const existing = await dbSAPPS.Account.findOne({
				where: { name: child.name },
				transaction,
			});
			if (existing) {
				// Cek dan update jika ada perubahan
				await checkAndUpdate(child, existing);
			} else {
				// Save child baru
				const account = await dbSAPPS.Account.create(child, { transaction });
				insertedIds.push(account.id);
			}
		}

		await transaction.commit();
		return {
			insertedIds,
			updatedIds,
			success: true,
			message: `Successfully processed ${params.length} accounts! Inserted: ${insertedIds.length}, Updated: ${updatedIds.length}`,
		};
	} catch (error) {
		await transaction.rollback();
		const errorMessage = error?.message || "Failed to import accounts, please try again!";
		console.error("Import error:", error); // Log untuk debugging
		return {
			success: false,
			message: errorMessage,
		};
	}
}

// Contoh penggunaan:
// const accountsData = [/* array of account objects dari sample data Anda */];
// importAll(accountsData).then(result => console.log(result));
