import * as THREE from 'three';

class NPC {
    constructor(name, position, type, color, dialogues) {
        this.name = name;
        this.position = position.clone();
        this.type = type;
        this.color = color;
        this.dialogues = dialogues;
        this.mesh = null;
        this.dialogIndex = 0;
        this.talked = false;

        // Патрулирование
        this.waypoints = [];
        this.currentWaypoint = 0;
        this.speed = 1.5;
        this.waitTimer = 0;
        this.isWaiting = false;
    }

    createMesh(scene) {
        const group = new THREE.Group();

        // Тело
        const bodyGeo = new THREE.CylinderGeometry(0.3, 0.35, 1.1, 8);
        const bodyMat = new THREE.MeshStandardMaterial({ color: this.color });
        const body = new THREE.Mesh(bodyGeo, bodyMat);
        body.position.y = 0.85;
        body.castShadow = true;
        group.add(body);

        // Голова
        const headGeo = new THREE.SphereGeometry(0.22, 8, 6);
        const headMat = new THREE.MeshStandardMaterial({ color: 0xd4a574 });
        const head = new THREE.Mesh(headGeo, headMat);
        head.position.y = 1.55;
        head.castShadow = true;
        group.add(head);

        // Руки
        const armMat = new THREE.MeshStandardMaterial({ color: this.color });
        [-0.4, 0.4].forEach(side => {
            const arm = new THREE.Mesh(new THREE.CylinderGeometry(0.08, 0.08, 0.7, 6), armMat);
            arm.position.set(side, 0.75, 0);
            arm.rotation.z = side > 0 ? -0.15 : 0.15;
            arm.castShadow = true;
            group.add(arm);
        });

        // Ноги
        const legMat = new THREE.MeshStandardMaterial({ color: 0x333344 });
        [-0.14, 0.14].forEach(side => {
            const leg = new THREE.Mesh(new THREE.CylinderGeometry(0.09, 0.09, 0.55, 6), legMat);
            leg.position.set(side, 0.28, 0);
            leg.castShadow = true;
            group.add(leg);
        });

        // Доп. элемент по типу NPC
        if (this.type === 'hobo') {
            const hatGeo = new THREE.CylinderGeometry(0.2, 0.26, 0.15, 8);
            const hatMat = new THREE.MeshStandardMaterial({ color: 0x444433 });
            const hat = new THREE.Mesh(hatGeo, hatMat);
            hat.position.y = 1.75;
            group.add(hat);
        } else if (this.type === 'citizen') {
            const bagGeo = new THREE.BoxGeometry(0.25, 0.35, 0.15);
            const bagMat = new THREE.MeshStandardMaterial({ color: 0x222222 });
            const bag = new THREE.Mesh(bagGeo, bagMat);
            bag.position.set(0.35, 0.8, 0);
            group.add(bag);
        }

        group.position.copy(this.position);
        scene.add(group);
        this.mesh = group;
    }

    setPatrol(points) {
        this.waypoints = points.map(p => new THREE.Vector3(p[0], 0, p[1]));
    }

    update(dt) {
        if (this.waypoints.length === 0) return;

        if (this.isWaiting) {
            this.waitTimer -= dt;
            if (this.waitTimer <= 0) this.isWaiting = false;
            return;
        }

        const target = this.waypoints[this.currentWaypoint];
        const dir = new THREE.Vector3().subVectors(target, this.position);
        dir.y = 0;
        const dist = dir.length();

        if (dist < 0.5) {
            this.currentWaypoint = (this.currentWaypoint + 1) % this.waypoints.length;
            this.isWaiting = true;
            this.waitTimer = 2 + Math.random() * 3;
            return;
        }

        dir.normalize();
        this.position.add(dir.multiplyScalar(this.speed * dt));
        this.mesh.position.copy(this.position);

        // Поворот к цели
        this.mesh.rotation.y = Math.atan2(dir.x, dir.z);
    }

    getDialogue() {
        const dialog = this.dialogues[this.dialogIndex];
        if (this.dialogIndex < this.dialogues.length - 1) {
            this.dialogIndex++;
        }
        this.talked = true;
        return dialog;
    }
}

export class NPCManager {
    constructor(game) {
        this.game = game;
        this.npcs = [];
    }

    spawnNPCs() {
        this.npcs = [];

        const configNPCs = this.game.world.mapConfig?.npcs;

        // Бомж-друг Серёга
        const seregaCfg = configNPCs?.find(n => n.name === 'Серёга') || {};
        const serega = new NPC(
            'Серёга',
            new THREE.Vector3(seregaCfg.x ?? -25, 0, seregaCfg.z ?? 30),
            'hobo',
            parseInt((seregaCfg.color || '#5a4a3a').replace('#',''), 16),
            [
                {
                    text: 'Здарова, братан! Ты новенький тут? Я Серёга. Слушай, совет: обыскивай мусорки — там можно найти бутылки. Сдашь их в магазине за деньги.',
                    choices: [
                        { text: 'Спасибо за совет!', effect: () => this.game.player.stats.mood += 5 },
                        { text: 'А где магазин?', effect: () => this.game.notify('Серёга показывает в сторону магазина на востоке.') }
                    ]
                },
                {
                    text: 'Ночью тут холодно, бро. Грейся у костра в укрытии, а то замёрзнешь. И не забывай есть — голод тут настоящий убийца.',
                    choices: [
                        { text: 'Понял, буду осторожен.', effect: () => {} },
                        { text: 'Может, вместе пойдём?', effect: () => this.game.notify('Серёга: "Нет, бро, я тут присмотрю за укрытием."') }
                    ]
                },
                {
                    text: 'Как дела, братан? Держись! Главное — не сдаваться. Я вот уже 3 года тут живу, и ничего, справляюсь.',
                    choices: [
                        { text: 'И ты держись, Серёга!', effect: () => { this.game.player.stats.mood += 3; } }
                    ]
                }
            ]
        );
        serega.setPatrol(seregaCfg.patrol || [[-25, 30], [-30, 28], [-25, 22], [-20, 28]]);

        // Прохожий
        const passerbyCfg = configNPCs?.find(n => n.name === 'Прохожий') || {};
        const passerby = new NPC(
            'Прохожий',
            new THREE.Vector3(passerbyCfg.x ?? 5, 0, passerbyCfg.z ?? -8),
            'citizen',
            parseInt((passerbyCfg.color || '#3355aa').replace('#',''), 16),
            [
                {
                    text: 'Чего тебе? А, бездомный... Ладно, вот тебе мелочь. Не пропей.',
                    choices: [
                        { text: 'Спасибо, добрый человек!', effect: () => { this.game.player.stats.money += 15; this.game.player.stats.mood += 5; this.game.notify('+15 ₽'); } },
                        { text: 'Мне не нужна подачка!', effect: () => { this.game.player.stats.mood += 2; this.game.notify('Вы сохранили достоинство.'); } }
                    ]
                },
                {
                    text: 'Опять ты... Слушай, мне некогда. Иди уже.',
                    choices: [
                        { text: '[Уйти]', effect: () => {} }
                    ]
                }
            ]
        );
        passerby.setPatrol(passerbyCfg.patrol || [[5, -8], [15, -8], [25, -8], [15, -8]]);

        // Бабушка
        const grannyCfg = configNPCs?.find(n => n.name === 'Бабушка Зина') || {};
        const granny = new NPC(
            'Бабушка Зина',
            new THREE.Vector3(grannyCfg.x ?? -28, 0, grannyCfg.z ?? 22),
            'citizen',
            parseInt((grannyCfg.color || '#886655').replace('#',''), 16),
            [
                {
                    text: 'Ох, сынок, жалко тебя... На вот, возьми хлебушек. Кушай, не стесняйся.',
                    choices: [
                        { text: 'Спасибо огромное!', effect: () => { this.game.inventory.addItem('bread', 2); this.game.player.stats.mood += 10; this.game.notify('Получено: Хлеб x2'); } },
                        { text: 'Благодарю, бабушка!', effect: () => { this.game.inventory.addItem('bread', 2); this.game.player.stats.mood += 10; this.game.notify('Получено: Хлеб x2'); } }
                    ]
                },
                {
                    text: 'А я вот каждый день в парке гуляю. Свежий воздух полезен. Ты тоже береги здоровье, сынок.',
                    choices: [
                        { text: 'Буду стараться, спасибо!', effect: () => { this.game.player.stats.mood += 3; } }
                    ]
                },
                {
                    text: 'Ты ещё тут, сынок? Держись. Вот, возьми ещё покушать.',
                    choices: [
                        { text: 'Спасибо, бабушка Зина!', effect: () => { this.game.inventory.addItem('can', 1); this.game.notify('Получено: Консервы'); } }
                    ]
                }
            ]
        );
        granny.setPatrol(grannyCfg.patrol || [[-28, 22], [-32, 26], [-28, 30], [-24, 26]]);

        // Охранник магазина
        const guardCfg = configNPCs?.find(n => n.name === 'Охранник') || {};
        const guard = new NPC(
            'Охранник',
            new THREE.Vector3(guardCfg.x ?? -20, 0, guardCfg.z ?? -14),
            'citizen',
            parseInt((guardCfg.color || '#222222').replace('#',''), 16),
            [
                {
                    text: 'Стой! В магазин можно, но только без фокусов. Украдёшь что — пожалеешь.',
                    choices: [
                        { text: 'Я просто хочу купить.', effect: () => {} },
                        { text: '[Кивнуть и пройти]', effect: () => {} }
                    ]
                },
                {
                    text: 'Ну что, опять ты. Давай без проблем.',
                    choices: [
                        { text: '[Кивнуть]', effect: () => {} }
                    ]
                }
            ]
        );

        // Батюшка у церкви
        const priestCfg = configNPCs?.find(n => n.name === 'Отец Михаил') || {};
        const priest = new NPC(
            'Отец Михаил',
            new THREE.Vector3(priestCfg.x ?? 30, 0, priestCfg.z ?? 58),
            'citizen',
            parseInt((priestCfg.color || '#222244').replace('#',''), 16),
            [
                {
                    text: 'Мир тебе, сын мой. Ты выглядишь усталым. Заходи в церковь — отдохнёшь в тепле. У нас всегда найдётся горячий чай и хлеб.',
                    choices: [
                        { text: 'Спасибо, отец Михаил.', effect: () => { this.game.player.stats.mood += 10; this.game.inventory.addItem('tea', 1); this.game.notify('Получено: Чай', 'good'); } },
                        { text: 'Мне ничего не нужно.', effect: () => {} }
                    ]
                },
                {
                    text: 'Каждый человек заслуживает второй шанс. Не теряй надежды. Приходи, когда будет тяжело — двери всегда открыты.',
                    choices: [
                        { text: 'Я буду помнить.', effect: () => { this.game.player.stats.mood += 8; } }
                    ]
                },
                {
                    text: 'Я вижу в тебе силу духа. Держись, и всё наладится. Вот, возьми — это поможет.',
                    choices: [
                        { text: 'Спасибо огромное!', effect: () => { this.game.inventory.addItem('bandage', 1); this.game.inventory.addItem('bread', 2); this.game.player.stats.mood += 15; this.game.notify('Получено: Бинт, Хлеб x2', 'good'); } }
                    ]
                }
            ]
        );
        priest.setPatrol(priestCfg.patrol || [[30, 58], [32, 55], [28, 55], [30, 58]]);

        // Бомж на стройке
        const builderCfg = configNPCs?.find(n => n.name === 'Михалыч') || {};
        const builder = new NPC(
            'Михалыч',
            new THREE.Vector3(builderCfg.x ?? 70, 0, builderCfg.z ?? 58),
            'hobo',
            parseInt((builderCfg.color || '#5a5a3a').replace('#',''), 16),
            [
                {
                    text: 'О, живой человек! Я тут на стройке обосновался — тепло, сухо, и никто не гонит. Ты тоже можешь переночевать тут.',
                    choices: [
                        { text: 'Спасибо за совет!', effect: () => { this.game.player.stats.mood += 5; } },
                        { text: 'А тут безопасно?', effect: () => { this.game.notify('Михалыч: "Ну... потолок не обвалится, думаю."'); } }
                    ]
                },
                {
                    text: 'Знаешь, я раньше строителем работал. Ирония, да? Теперь на чужой стройке живу. Но навыки пригодились — я себе тут угол обустроил.',
                    choices: [
                        { text: 'Жизнь бывает несправедлива.', effect: () => { this.game.player.stats.mood += 3; } },
                        { text: 'Может, ещё устроишься?', effect: () => { this.game.notify('Михалыч вздыхает: "Может быть..."'); this.game.player.stats.mood += 2; } }
                    ]
                },
                {
                    text: 'На вот, нашёл тут кое-что полезное. Бери, мне не нужно.',
                    choices: [
                        { text: 'Спасибо, Михалыч!', effect: () => { this.game.inventory.addItem('scrap', 2); this.game.inventory.addItem('rope', 1); this.game.notify('Получено: Хлам x2, Верёвка', 'good'); } }
                    ]
                }
            ]
        );
        builder.setPatrol(builderCfg.patrol || [[70, 58], [73, 60], [67, 62], [70, 58]]);

        this.npcs = [serega, passerby, granny, guard, priest, builder];

        this.npcs.forEach(npc => {
            npc.createMesh(this.game.scene);
        });
    }

    spawnPassersby() {
        this.passersby = [];
        const colors = [0x3355aa, 0xaa3355, 0x33aa55, 0x555555, 0x8855aa, 0xaa8833, 0x338888, 0x885533];

        // Маршруты по тротуарам всех дорог
        const configRoutes = this.game.world.mapConfig?.passerbyRoutes;
        const sidewalkRoutes = configRoutes || [
            // EW Главная — северный тротуар (z=8) — на восток
            { waypoints: [[-80, 8], [-40, 8], [0, 8], [30, 8], [60, 8], [80, 8]] },
            // EW Главная — южный тротуар (z=-8) — на запад
            { waypoints: [[80, -8], [40, -8], [0, -8], [-30, -8], [-60, -8], [-80, -8]] },
            // EW Южная — тротуар z=-35 — на восток
            { waypoints: [[-80, -35], [-30, -35], [20, -35], [60, -35], [80, -35]] },
            // EW Южная — тротуар z=-45 — на запад
            { waypoints: [[80, -45], [40, -45], [0, -45], [-40, -45], [-80, -45]] },
            // EW Северная — тротуар z=46 — на восток
            { waypoints: [[-70, 46], [-30, 46], [10, 46], [40, 46], [70, 46]] },
            // EW Северная — тротуар z=54 — на запад
            { waypoints: [[70, 54], [30, 54], [0, 54], [-30, 54], [-70, 54]] },
            // NS Главная — тротуар x=8 — на север
            { waypoints: [[8, -60], [8, -35], [8, -8], [8, 8], [8, 30], [8, 60]] },
            // NS Главная — тротуар x=-8 — на юг
            { waypoints: [[-8, 60], [-8, 30], [-8, 8], [-8, -8], [-8, -35], [-8, -60]] },
            // NS Восточная — тротуар x=46 — на север
            { waypoints: [[46, -45], [46, -20], [46, 0], [46, 25], [46, 45]] },
            // NS Западная — тротуар x=-56 — на юг
            { waypoints: [[-56, 45], [-56, 25], [-56, 0], [-56, -20], [-56, -45]] },
        ];

        for (let i = 0; i < 10; i++) {
            const routeData = sidewalkRoutes[i % sidewalkRoutes.length];
            const color = colors[Math.floor(Math.random() * colors.length)];
            const wps = routeData.waypoints;
            const pb = {
                mesh: null,
                position: new THREE.Vector3(wps[0][0], 0, wps[0][1]),
                waypoints: wps.map(w => new THREE.Vector3(w[0], 0, w[1])),
                currentWP: 0,
                speed: 1.5 + Math.random() * 1.0,
                color,
                delay: i * 6 + Math.random() * 10,
                waitTimer: 0,
            };

            const group = new THREE.Group();
            const bodyMat = new THREE.MeshStandardMaterial({ color });
            const body = new THREE.Mesh(new THREE.CylinderGeometry(0.25, 0.3, 1, 8), bodyMat);
            body.position.y = 0.8;
            body.castShadow = true;
            group.add(body);

            const head = new THREE.Mesh(
                new THREE.SphereGeometry(0.18, 8, 6),
                new THREE.MeshStandardMaterial({ color: 0xd4a574 })
            );
            head.position.y = 1.45;
            group.add(head);

            // Руки
            const armMat = new THREE.MeshStandardMaterial({ color });
            [-0.35, 0.35].forEach(side => {
                const arm = new THREE.Mesh(new THREE.CylinderGeometry(0.07, 0.07, 0.6, 6), armMat);
                arm.position.set(side, 0.65, 0);
                arm.rotation.z = side > 0 ? -0.15 : 0.15;
                arm.castShadow = true;
                group.add(arm);
            });

            // Ноги
            const legMat = new THREE.MeshStandardMaterial({ color: 0x333344 });
            [-0.12, 0.12].forEach(side => {
                const leg = new THREE.Mesh(new THREE.CylinderGeometry(0.08, 0.08, 0.5, 6), legMat);
                leg.position.set(side, 0.25, 0);
                leg.castShadow = true;
                group.add(leg);
            });

            group.position.copy(pb.position);
            group.visible = false;
            this.game.scene.add(group);
            pb.mesh = group;

            this.passersby.push(pb);
        }
    }

    update(dt) {
        this.npcs.forEach(npc => npc.update(dt));

        // Прохожие — ходят по путевым точкам вдоль тротуаров
        if (this.passersby) {
            this.passersby.forEach(pb => {
                if (pb.delay > 0) {
                    pb.delay -= dt;
                    return;
                }
                pb.mesh.visible = true;

                // Ожидание на точке
                if (pb.waitTimer > 0) {
                    pb.waitTimer -= dt;
                    return;
                }

                const target = pb.waypoints[pb.currentWP];
                const dir = new THREE.Vector3().subVectors(target, pb.position);
                dir.y = 0;
                const dist = dir.length();

                if (dist < 1) {
                    pb.currentWP++;
                    // Иногда останавливаемся на точке
                    if (Math.random() < 0.3) {
                        pb.waitTimer = 1 + Math.random() * 3;
                    }
                    if (pb.currentWP >= pb.waypoints.length) {
                        // Прошёл маршрут — телепортируем на старт
                        pb.currentWP = 0;
                        pb.position.copy(pb.waypoints[0]);
                        pb.mesh.position.copy(pb.position);
                        pb.delay = 8 + Math.random() * 15;
                        pb.mesh.visible = false;
                    }
                    return;
                }

                dir.normalize();
                pb.position.add(dir.multiplyScalar(pb.speed * dt));
                pb.mesh.position.copy(pb.position);
                pb.mesh.rotation.y = Math.atan2(dir.x, dir.z);
            });
        }

        // Кулдауны мусорок
        this.game.world.interactables.forEach(obj => {
            if (obj.searchCooldown > 0) {
                obj.searchCooldown -= this.game.timeSpeed * dt;
            }
        });
    }

    talkTo(npc) {
        const dialog = npc.getDialogue();
        const rep = this.game.reputation.value;

        // Репутация влияет на текст
        let extraText = '';
        if (rep >= 50 && npc.type === 'citizen') {
            extraText = '\n(Относится к вам с уважением)';
        } else if (rep <= -30 && npc.type === 'citizen') {
            extraText = '\n(Смотрит с подозрением)';
        }

        const choices = dialog.choices.map(c => c.text);

        // Бонусная опция при высокой репутации
        if (rep >= 40 && npc.type === 'citizen' && !npc._repBonusGiven) {
            choices.push('[Репутация] Попросить помощь');
        }

        this.game.sound.playDialogOpen();
        this.game.ui.showDialog(npc.name, dialog.text + extraText, choices, (index) => {
            if (index < dialog.choices.length) {
                dialog.choices[index].effect();
            } else if (rep >= 40 && !npc._repBonusGiven) {
                npc._repBonusGiven = true;
                const roll = Math.random();
                if (roll < 0.5) {
                    const amount = 30 + Math.floor(Math.random() * 40);
                    this.game.player.stats.money += amount;
                    this.game.sound.playCoin();
                    this.game.notify(`${npc.name} дал вам ${amount}₽!`, 'good');
                } else {
                    this.game.inventory.addItem('bread', 1);
                    this.game.inventory.addItem('tea', 1);
                    this.game.sound.playPickup();
                    this.game.notify(`${npc.name} дал вам еду!`, 'good');
                }
            }
            this.game.ui.hideDialog();
            this.game.questSystem.onEvent('talk_npc', npc.name);
            this.game.reputation.change(1);

            // Трекинг для достижений
            this.game.talkedNPCs.add(npc.name);
            if (this.game.talkedNPCs.size >= 3) {
                this.game.achievements.check('first_talk');
            }
            if (this.game.talkedNPCs.size >= this.npcs.length) {
                this.game.achievements.check('all_npcs');
            }
        });
    }
}
