const { Client } = require('pg');
const shapefile = require('shapefile');
const crypto = require('node:crypto');

const firstNames = ['Hans', 'Peter', 'Thomas', 'Michael', 'Andreas', 'Wolfgang', 'Klaus', 'Jürgen', 'Günter', 'Christian', 'Maria', 'Ursula', 'Monika', 'Petra', 'Elisabeth', 'Sabine', 'Renate', 'Karin', 'Helga', 'Gisela'];
const lastNames = ['Müller', 'Schmidt', 'Schneider', 'Fischer', 'Weber', 'Meyer', 'Wagner', 'Becker', 'Schulz', 'Hoffmann', 'Schäfer', 'Koch', 'Bauer', 'Richter', 'Klein', 'Wolf', 'Schröder', 'Neumann', 'Schwarz', 'Zimmermann'];

function getRandomElement(arr) {
    return arr[Math.floor(Math.random() * arr.length)];
}

function getRandomStatus() {
    const val = Math.random();
    if (val < 0.1) return 'Gesichert';
    if (val < 0.3) return 'In Verhandlung';
    return 'Offen';
}

function geojsonToWkt(geom) {
    if (geom.type === 'Polygon') {
        const rings = geom.coordinates.map(ring => 
            '(' + ring.map(pt => `${pt[0]} ${pt[1]}`).join(', ') + ')'
        ).join(', ');
        return `MULTIPOLYGON((${rings}))`;
    } else if (geom.type === 'MultiPolygon') {
        const polys = geom.coordinates.map(poly => 
            '(' + poly.map(ring => 
                '(' + ring.map(pt => `${pt[0]} ${pt[1]}`).join(', ') + ')'
            ).join(', ') + ')'
        ).join(', ');
        return `MULTIPOLYGON(${polys})`;
    } else if (geom.type === 'Point') {
        return `POINT(${geom.coordinates[0]} ${geom.coordinates[1]})`;
    }
    throw new Error('Unsupported geometry type: ' + geom.type);
}

async function run() {
    const client = new Client({
        host: '87.106.21.21',
        port: 5432,
        user: 'enwelo_admin',
        password: 'WX1t1cgP1qK09',
        database: 'enwelo'
    });

    try {
        await client.connect();
        console.log("Connected to database.");

        // 1. Ensure project 'test' exists
        let projectUuid;
        const checkProj = await client.query("SELECT id FROM geodaten.projekte WHERE name = 'test';");
        if (checkProj.rows.length > 0) {
            projectUuid = checkProj.rows[0].id;
            console.log(`Project 'test' already exists with UUID: ${projectUuid}`);
        } else {
            projectUuid = crypto.randomUUID();
            await client.query("INSERT INTO geodaten.projekte (id, name, beschreibung) VALUES ($1, $2, $3);", [projectUuid, 'test', 'Testprojekt für Dummydaten']);
            console.log(`Created project 'test' with UUID: ${projectUuid}`);
        }

        // 2. Update turbine where project_id IS NULL to 'test'
        console.log("Updating wind turbine...");
        const weaUpdate = await client.query(
            `UPDATE geodaten.wea_standorte 
             SET projekt_id = 'test', wea_nummer = COALESCE(wea_nummer, '1') 
             WHERE projekt_id IS NULL OR projekt_id = '' 
             RETURNING id, ST_AsText(geom) as geom_wkt;`
        );
        console.log(`Updated ${weaUpdate.rowCount} wind turbine(s) to project 'test'.`);

        // 3. Import Flurstücke
        console.log("Reading Flurstücke shapefile...");
        const flurstuecke = await shapefile.read("Shapefile/Test/Flurstücke.shp");
        console.log(`Found ${flurstuecke.features.length} flurstücke features.`);

        let insertedAlkis = 0;
        let insertedZuweisung = 0;
        let insertedStatus = 0;

        for (let i = 0; i < flurstuecke.features.length; i++) {
            const f = flurstuecke.features[i];
            const props = f.properties;
            const fsk = props.flstkennz || props.FSK;
            if (!fsk) continue;

            const wkt = geojsonToWkt(f.geometry);
            
            // Check if ALKIS owner entry already exists
            const checkAlkis = await client.query('SELECT 1 FROM geodaten.flaecheneigentuemer_alkis WHERE "FSK" = $1;', [fsk]);
            if (checkAlkis.rows.length === 0) {
                const gna = getRandomElement(lastNames);
                const vna = getRandomElement(firstNames);
                const gemarkung = props.gemarkung || props.GMK__BEZ || '';
                const flur = parseInt(props.flur || props.FLN) || null;
                const gemeinde = props.gemeinde || props.GEM__BEZ || '';

                await client.query(
                    `INSERT INTO geodaten.flaecheneigentuemer_alkis ("FSK", "GNA", "VNA", "GMK__BEZ", "FLN", "GEM__BEZ", geom) 
                     VALUES ($1, $2, $3, $4, $5, $6, ST_SetSRID(ST_GeomFromText($7), 25832));`,
                    [fsk, gna, vna, gemarkung, flur, gemeinde, wkt]
                );
                insertedAlkis++;
            }

            // Check if project assignment exists
            const checkZuw = await client.query('SELECT 1 FROM geodaten.flaecheneigentuemer_alkis_zuweisung WHERE fsk = $1 AND projekt_id = $2;', [fsk, projectUuid]);
            if (checkZuw.rows.length === 0) {
                await client.query(
                    `INSERT INTO geodaten.flaecheneigentuemer_alkis_zuweisung (id, fsk, projekt_id, zugewiesen_am) 
                     VALUES ($1, $2, $3, NOW());`,
                    [crypto.randomUUID(), fsk, projectUuid]
                );
                insertedZuweisung++;
            }

            // Check if status entry exists
            const checkStat = await client.query('SELECT 1 FROM geodaten.flaecheneigentuemer_status WHERE fsk = $1 AND projekt_id = $2;', [fsk, projectUuid]);
            if (checkStat.rows.length === 0) {
                const status = getRandomStatus();
                await client.query(
                    `INSERT INTO geodaten.flaecheneigentuemer_status (id, fsk, projekt_id, status, datum) 
                     VALUES ($1, $2, $3, $4, NOW());`,
                    [crypto.randomUUID(), fsk, projectUuid, status]
                );
                insertedStatus++;
            }

            if ((i + 1) % 200 === 0) {
                console.log(`Processed ${i + 1} / ${flurstuecke.features.length} flurstücke...`);
            }
        }
        console.log(`Flurstücke summary: Inserted ${insertedAlkis} owners, ${insertedZuweisung} assignments, ${insertedStatus} status values.`);

        // 4. Import Wohngebäude
        console.log("Reading Wohngebäude shapefile...");
        const wohngebaeude = await shapefile.read("Shapefile/Test/Wohngebäude.shp");
        console.log(`Found ${wohngebaeude.features.length} wohngebäude features.`);

        let insertedWohn = 0;
        for (let i = 0; i < wohngebaeude.features.length; i++) {
            const f = wohngebaeude.features[i];
            const props = f.properties;
            const wkt = geojsonToWkt(f.geometry);

            const oi = props.OI || '';
            const ags = props.AGS || '';
            const gfk = props.GFK || '';
            const aktualitaet = props.AKTUALITAE || props.AKTUALITÄT || '';
            const wert = props.WERT !== undefined ? parseInt(props.WERT) : null;
            const axGeb = props.AX_Gebäude !== undefined ? parseInt(props.AX_Gebäude) : (props.AX_Gebäud !== undefined ? parseInt(props.AX_Gebäud) : null);
            const randPoint = props.rand_point !== undefined ? parseInt(props.rand_point) : null;

            // Check if building already exists based on geometry/identifier (or just insert since it's dummy data, but let's check OI to avoid duplicates)
            const checkWohn = await client.query('SELECT 1 FROM geodaten.wohngebeaude WHERE "OI" = $1;', [oi]);
            if (checkWohn.rows.length === 0) {
                await client.query(
                    `INSERT INTO geodaten.wohngebeaude (geom, rand_point_id, "AGS", "OI", "GFK", "AKTUALITAE", "WERT", "AX_Gebäude") 
                     VALUES (ST_SetSRID(ST_GeomFromText($1), 25832), $2, $3, $4, $5, $6, $7, $8);`,
                    [wkt, randPoint, ags, oi, gfk, aktualitaet, wert, axGeb]
                );
                insertedWohn++;
            }

            if ((i + 1) % 500 === 0) {
                console.log(`Processed ${i + 1} / ${wohngebaeude.features.length} wohngebäude...`);
            }
        }
        console.log(`Wohngebäude summary: Inserted ${insertedWohn} new residential buildings.`);

        console.log("Successfully completed data import!");

    } catch (e) {
        console.error("Database transaction error:", e);
    } finally {
        await client.end();
    }
}
run();
