import fs from "node:fs/promises"
import path from "node:path"
import https from "node:https"

const DEFAULT_SOURCE_URL =
    "https://www.bundesbank.de/resource/blob/602632/bec25ca5df1eb62fefadd8325dafe67c/472B63F073F071307366337C94F8C870/blz-aktuell-txt-data.txt"

const OUTPUT_NAME_FILE = path.resolve("src/utils/deBankCodes.ts")
const OUTPUT_BIC_FILE = path.resolve("src/utils/deBankBics.ts")

function fetchBuffer(url: string): Promise<Buffer> {
    return new Promise((resolve, reject) => {
        https
            .get(url, (res) => {
                if (res.statusCode && res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
                    return resolve(fetchBuffer(res.headers.location))
                }

                if (res.statusCode !== 200) {
                    return reject(new Error(`Download failed with status ${res.statusCode}`))
                }

                const chunks: Buffer[] = []
                res.on("data", (chunk) => chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)))
                res.on("end", () => resolve(Buffer.concat(chunks)))
                res.on("error", reject)
            })
            .on("error", reject)
    })
}

function escapeTsString(value: string) {
    return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')
}

async function main() {
    const source = process.env.BLZ_SOURCE_URL || DEFAULT_SOURCE_URL
    const sourceFile = process.env.BLZ_SOURCE_FILE
    let raw: Buffer

    if (sourceFile) {
        console.log(`Reading BLZ source file: ${sourceFile}`)
        raw = await fs.readFile(sourceFile)
    } else {
        console.log(`Downloading BLZ source: ${source}`)
        raw = await fetchBuffer(source)
    }
    const content = raw.toString("latin1")

    const lines = content.split(/\r?\n/)
    const nameMap = new Map<string, string>()
    const bicMap = new Map<string, string>()

    for (const line of lines) {
        if (!line || line.length < 150) continue
        const blz = line.slice(0, 8).trim()
        const name = line.slice(9, 67).trim()
        const bic = line.slice(139, 150).trim()

        if (!/^\d{8}$/.test(blz) || !name) continue
        if (!nameMap.has(blz)) nameMap.set(blz, name)
        if (bic && !bicMap.has(blz)) bicMap.set(blz, bic)
    }

    const sortedNames = [...nameMap.entries()].sort(([a], [b]) => a.localeCompare(b))
    const sortedBics = [...bicMap.entries()].sort(([a], [b]) => a.localeCompare(b))

    const nameOutputLines = [
        "// Lokale Bankleitzahl-zu-Institut Zuordnung (DE).",
        "// Quelle: Deutsche Bundesbank, BLZ-Datei (vollstaendig).",
        "export const DE_BANK_CODE_TO_NAME: Record<string, string> = {",
        ...sortedNames.map(([blz, name]) => `    "${blz}": "${escapeTsString(name)}",`),
        "}",
        "",
    ]

    const bicOutputLines = [
        "// Lokale Bankleitzahl-zu-BIC Zuordnung (DE).",
        "// Quelle: Deutsche Bundesbank, BLZ-Datei (vollstaendig).",
        "export const DE_BANK_CODE_TO_BIC: Record<string, string> = {",
        ...sortedBics.map(([blz, bic]) => `    "${blz}": "${escapeTsString(bic)}",`),
        "}",
        "",
    ]

    await fs.writeFile(OUTPUT_NAME_FILE, nameOutputLines.join("\n"), "utf8")
    await fs.writeFile(OUTPUT_BIC_FILE, bicOutputLines.join("\n"), "utf8")
    console.log(`Wrote ${sortedNames.length} bank names to ${OUTPUT_NAME_FILE}`)
    console.log(`Wrote ${sortedBics.length} bank BICs to ${OUTPUT_BIC_FILE}`)
}

main().catch((err) => {
    console.error(err)
    process.exit(1)
})
