import Base from "./base";
import { promises as fs } from "fs";
import { Card, DBReader } from "./dbreader";
import { CNOCGFetcher } from "./cnocg";

export class DirectFetcher extends Base {
	static async fetchOnce() {
		const fetcher = new DirectFetcher({ name: "Temp Direct Fetcher", level: 'debug' });
		await fetcher.init();
		return await fetcher.fetch();
	}
	cardCodes: number[] = [];
	private addCode(code: number) {
		const posToRemove: number[] = [];
		for (let i = 0; i < this.cardCodes.length; ++i) {
			const c = this.cardCodes[i];
			// 完全相同的不加入
			if (c === code) {
				this.log.debug(`Skipped full dup: ${code} ${c}`);
				return;
			}
			const codeDifference = code - c;

			// 新加入的卡号比某一卡号大，并且 10 以内，则新的卡是那张卡的关联卡，不入。
			if (codeDifference > 0 && codeDifference <= 20) {
				this.log.debug(`Skipped forward-related dup: ${code} ${c}`);
				return;
			}

			// 新加入的卡号比某一卡号小，并且 10 以内，则把旧的卡删掉。-
			if (codeDifference < 0 && codeDifference >= -20) {
				this.log.debug(`Would remove backword-related dup: ${code} ${c}`);
				posToRemove.push(i);
			}
		}
		posToRemove.sort((a, b) => b - a);
		for (const pos of posToRemove) {
			const codeRemoved = this.cardCodes.splice(pos, 1);
			this.log.debug(`Removed backword-related dup: ${codeRemoved}`);
		}
		this.cardCodes.push(code);
	} 

	private async workWithYdk(ydkFile: string) {
		this.log.info(`Reading ${ydkFile}.`);
		const content = await fs.readFile(`./packs/${ydkFile}`, 'utf-8');
		for (let line of content.split('\n')) {
			const match = line.trim().match(/^(\d{5,9})$/);
			if (!match) {
				continue;
			}
			const code = parseInt(match[1]);
			this.addCode(code);
		}
	}

	private async workWithExisting() {
		const cnDb = await new DBReader({ name: 'Existing Reader', level: 'info' }).openDatabase(this.config.cnDatabasePath);
		this.log.info(`Reading existing YGOPro database.`);
		const cnDbData = await cnDb.all<{ id: number }[]>("SELECT id FROM datas where (ot & 0x8) > 0 and (type & 0x4000) = 0");
		this.log.info(`${cnDbData.length} existing cards found.`);
		for (const row of cnDbData) {
			this.addCode(row.id);
		}
	}

	async fetch(): Promise<Card[]> {
		//this.log.info(`Started fetching from CNOCG.`);
		this.cardCodes = [];
		this.log.info(`Started reading from ydk cards.`);
		const ydkFiles = await fs.readdir('./packs');
		this.log.info(`${ydkFiles.length} packs found.`);
		for (let file of ydkFiles) {
			await this.workWithYdk(file);
		}
		await this.workWithExisting();
		const finalCodes = this.cardCodes;
		this.log.info(`${finalCodes.length} cards in total.`);
		return finalCodes.map(code => new Card(code));
	}
}
