import * as THREE from 'three';
import { World } from './World.js';
import { Player } from './Player.js';
import { CameraController } from './Camera.js';
import { NPCManager } from './NPC.js';
import { Inventory } from './Inventory.js';
import { QuestSystem } from './QuestSystem.js';
import { UI } from './UI.js';
import { ParticleSystem } from './Particles.js';
import { Weather } from './Weather.js';
import { SaveSystem } from './SaveSystem.js';
import { SoundManager } from './SoundManager.js';
import { EventSystem } from './Events.js';
import { Dog } from './Dog.js';
import { Skills } from './Skills.js';
import { Reputation } from './Reputation.js';
import { JobSystem } from './JobSystem.js';
import { Seasons } from './Seasons.js';
import { Dangers } from './Dangers.js';
import { Equipment } from './Equipment.js';
import { Achievements } from './Achievements.js';
import { Housing } from './Housing.js';
import { Police } from './Police.js';
import { Interiors } from './Interiors.js';

export class Game {
    constructor(canvas) {
        this.canvas = canvas;
        this.clock = new THREE.Clock();
        this.running = false;
        this.paused = false;

        // Время
        this.gameTime = 8 * 60;
        this.gameDay = 1;
        this.timeSpeed = 1.5;

        // Статистика
        this.totalJobsCompleted = 0;
        this.totalBottlesSold = 0;
        this.totalCrafted = 0;
        this.talkedNPCs = new Set();
        this.visitedLocations = new Set();
        this.enemiesDefeated = 0;
        this.consecutiveFights = 0;

        // Renderer
        this.renderer = new THREE.WebGLRenderer({ canvas, antialias: true });
        this.renderer.setSize(window.innerWidth, window.innerHeight);
        this.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
        this.renderer.shadowMap.enabled = true;
        this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
        this.renderer.toneMapping = THREE.ACESFilmicToneMapping;
        this.renderer.toneMappingExposure = 1.0;

        // Scene
        this.scene = new THREE.Scene();
        this.scene.background = new THREE.Color(0x87CEEB);
        this.scene.fog = new THREE.Fog(0x87CEEB, 80, 200);

        // Camera
        this.camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 300);
        this.camera.layers.enable(0);
        this.camera.layers.disable(1);

        // Core systems
        this.world = new World(this);
        this.player = new Player(this);
        this.cameraController = new CameraController(this);
        this.npcManager = new NPCManager(this);
        this.inventory = new Inventory(this);
        this.questSystem = new QuestSystem(this);
        this.ui = new UI(this);

        // Extended systems
        this.particles = new ParticleSystem(this);
        this.weather = new Weather(this);
        this.saveSystem = new SaveSystem(this);
        this.sound = new SoundManager(this);
        this.events = new EventSystem(this);
        this.dog = new Dog(this);
        this.skills = new Skills(this);
        this.reputation = new Reputation(this);
        this.jobSystem = new JobSystem(this);
        this.seasons = new Seasons(this);
        this.dangers = new Dangers(this);

        // New systems
        this.equipment = new Equipment(this);
        this.achievements = new Achievements(this);
        this.housing = new Housing(this);
        this.police = new Police(this);
        this.interiors = new Interiors(this);

        // Night sky
        this.stars = null;
        this.moon = null;

        // Input
        this.keys = {};
        this.setupInput();

        window.addEventListener('resize', () => this.onResize());
    }

    async start() {
        this.running = true;
        this.paused = true;
        this.sound.init();
        await this.world.build();
        this.housing.initFromConfig();
        this.player.spawn();
        this.npcManager.spawnNPCs();
        this.questSystem.initQuests();
        this.weather.init();
        this.ui.init();
        this.initParticles();
        this.createNightSky();
        this.dog.spawn();
        this.npcManager.spawnPassersby();
        this.jobSystem.init();
        this.world.createVehicles();
        this.police.spawnPatrols();
        this.animate();

        // Показать интро
        this.ui.showIntro(() => {
            this.paused = false;
            this.canvas.requestPointerLock();
        });
    }

    async startFromSave() {
        this.running = true;
        this.sound.init();
        await this.world.build();
        this.housing.initFromConfig();
        this.player.spawn();
        this.npcManager.spawnNPCs();
        this.questSystem.initQuests();
        this.weather.init();
        this.ui.init();
        this.initParticles();
        this.createNightSky();
        this.dog.spawn();
        this.npcManager.spawnPassersby();
        this.jobSystem.init();
        this.world.createVehicles();
        this.police.spawnPatrols();
        this.saveSystem.load();
        this.animate();
    }

    initParticles() {
        const shelterCfg = this.world.mapConfig?.structures?.shelter || {};
        const fireX = (shelterCfg.x ?? -35) - 2;
        const fireZ = shelterCfg.z ?? 35;
        this.particles.createFire(new THREE.Vector3(fireX, 0.3, fireZ));
        this.particles.createRain();
        this.particles.createSnow();
    }

    createNightSky() {
        // Звёзды
        const starCount = 800;
        const starGeo = new THREE.BufferGeometry();
        const starPos = new Float32Array(starCount * 3);
        for (let i = 0; i < starCount; i++) {
            const theta = Math.random() * Math.PI * 2;
            const phi = Math.random() * Math.PI * 0.5;
            const r = 250;
            starPos[i * 3]     = Math.cos(theta) * Math.sin(phi) * r;
            starPos[i * 3 + 1] = Math.cos(phi) * r;
            starPos[i * 3 + 2] = Math.sin(theta) * Math.sin(phi) * r;
        }
        starGeo.setAttribute('position', new THREE.BufferAttribute(starPos, 3));

        const starMat = new THREE.PointsMaterial({
            color: 0xffffff,
            size: 0.8,
            transparent: true,
            opacity: 0,
            depthWrite: false
        });
        this.stars = new THREE.Points(starGeo, starMat);
        this.scene.add(this.stars);

        // Луна
        const moonGeo = new THREE.SphereGeometry(5, 16, 16);
        const moonMat = new THREE.MeshBasicMaterial({
            color: 0xffffee,
            transparent: true,
            opacity: 0
        });
        this.moon = new THREE.Mesh(moonGeo, moonMat);
        this.moon.position.set(-100, 120, -80);
        this.scene.add(this.moon);
    }

    animate() {
        if (!this.running) return;
        requestAnimationFrame(() => this.animate());

        const dt = Math.min(this.clock.getDelta(), 0.1);
        if (this.paused) return;

        // Игровое время
        this.gameTime += this.timeSpeed * dt;
        if (this.gameTime >= 24 * 60) {
            this.gameTime -= 24 * 60;
            this.gameDay++;
        }

        // Все системы
        this.world.updateLighting(this.gameTime);
        this.world.updateVehicles(dt);
        this.player.update(dt);
        this.cameraController.update(dt);
        this.npcManager.update(dt);
        this.questSystem.update(dt);
        this.weather.update(dt);
        this.particles.update(dt);
        this.events.update(dt);
        this.dog.update(dt);
        this.seasons.update();
        this.jobSystem.update(dt);
        this.dangers.update(dt);
        this.police.update(dt);
        this.achievements.updateChecks();
        this.ui.update(dt);

        // Ночное небо
        this.updateNightSky();

        // Амбиент
        this.updateAmbientSound();

        // Рендер
        this.renderer.render(this.scene, this.camera);
    }

    updateNightSky() {
        const hour = this.gameTime / 60;
        let nightFactor = 0;

        if (hour < 5) nightFactor = 1;
        else if (hour < 7) nightFactor = 1 - (hour - 5) / 2;
        else if (hour > 19 && hour < 21) nightFactor = (hour - 19) / 2;
        else if (hour >= 21) nightFactor = 1;

        if (this.stars) {
            this.stars.material.opacity = nightFactor * 0.8;
            this.stars.rotation.y += 0.00005;
        }
        if (this.moon) {
            this.moon.material.opacity = nightFactor * 0.9;
            const moonAngle = ((hour - 18) / 12) * Math.PI;
            this.moon.position.set(
                Math.cos(moonAngle) * 100,
                Math.sin(moonAngle) * 100 + 40,
                -80
            );
        }
    }

    updateAmbientSound() {
        if (this.weather.current === 'rain') {
            this.sound.playAmbient('rain');
        } else if (this.isNight()) {
            this.sound.playAmbient('night');
        } else {
            this.sound.stopAmbient();
        }
    }

    setupInput() {
        document.addEventListener('keydown', (e) => {
            if (!this.running) return;
            this.keys[e.code] = true;

            if (e.code === 'KeyE') this.player.interact();
            if (e.code === 'KeyI') this.ui.toggleInventory();
            if (e.code === 'KeyQ') this.ui.toggleQuests();
            if (e.code === 'KeyJ') this.ui.toggleSkills();
            if (e.code === 'KeyU') this.ui.toggleAchievements();
            if (e.code === 'KeyF') this.player.startBegging();
            if (e.code === 'KeyG') this.player.startBusking();
            if (e.code === 'KeyM') {
                const on = this.sound.toggle();
                this.notify(on ? 'Звук включён' : 'Звук выключен');
            }
            if (e.code === 'Space') {
                this.dangers.playerFightBack();
            }
            if (e.code === 'KeyH') {
                this.jobSystem.cancelJob();
            }
            if (e.code === 'F5') {
                e.preventDefault();
                this.saveSystem.save();
            }
        });

        document.addEventListener('keyup', (e) => {
            this.keys[e.code] = false;
            if (e.code === 'KeyF') this.player.stopBegging();
            if (e.code === 'KeyG') this.player.stopBusking();
        });
    }

    onResize() {
        this.camera.aspect = window.innerWidth / window.innerHeight;
        this.camera.updateProjectionMatrix();
        this.renderer.setSize(window.innerWidth, window.innerHeight);
    }

    getTimeString() {
        const h = Math.floor(this.gameTime / 60) % 24;
        const m = Math.floor(this.gameTime % 60);
        return `${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}`;
    }

    isNight() {
        const h = this.gameTime / 60;
        return h < 6 || h > 21;
    }

    notify(text, type) {
        this.ui.showNotification(text, type);
    }

    gameOver(reason) {
        this.running = false;
        this.sound.stopAmbient();
        this.sound.playHurt();
        this.dangers.reset();
        this.ui.showDeathScreen(reason, this.gameDay);
        document.exitPointerLock();
    }

    async restart() {
        this.scene.clear();
        this.particles.clear();
        this.gameTime = 8 * 60;
        this.gameDay = 1;
        this.totalJobsCompleted = 0;
        this.totalBottlesSold = 0;
        this.totalCrafted = 0;
        this.talkedNPCs = new Set();
        this.visitedLocations = new Set();
        this.enemiesDefeated = 0;
        this.consecutiveFights = 0;
        this.player.reset();
        this.inventory.reset();
        this.questSystem.reset();
        this.weather.reset();
        this.events.reset();
        this.dog.reset();
        this.skills.reset();
        this.reputation.reset();
        this.jobSystem.reset();
        this.seasons.reset();
        this.dangers.reset();
        this.police.reset();
        this.interiors.reset();
        this.equipment.reset();
        this.achievements.reset();
        this.housing.reset();
        await this.world.build();
        this.housing.initFromConfig();
        this.world.createVehicles();
        this.player.spawn();
        this.npcManager.spawnNPCs();
        this.npcManager.spawnPassersby();
        this.questSystem.initQuests();
        this.initParticles();
        this.createNightSky();
        this.dog.spawn();
        this.police.spawnPatrols();
        this.ui.hideDeathScreen();
        this.running = true;
        this.clock.getDelta();
        this.animate();
    }
}
