import { GameObject } from "./gameObject.js";
import { loadAntById } from "./loadJson.js";
import { gameTime } from "./gameTime.js";
import { loadSprite } from "./loadSprite.js";
import { currency } from "./currency.js";
import { resources } from "./resource.js";
import { signalantArray } from "./signalant.js";
import { totalStats } from "./totalStats.js";
import { tutorial } from "./tutorial.js";

export let antArray = [];

function normalizeDirection(direction) {
    return ((direction % 360) + 360) % 360;
}

export class Ant extends GameObject {
    constructor(id, color, type, x, y, direction, options = {}) {
        super(id, options);
        this.color = color;
        this.type = type;
        this.initialStats = options.stats ? { ...options.stats } : null;
        this.setAnimation(`assets/ants/${color}_${type}`, 4);
        this.setPosition(x, y);
        this.direction = direction;
        this.setSize(options.width || 16, options.height || 13);

        this.distanceTraveled = 0;
        this.returnDistanceRemaining = 0;
        this.state = "outbound";
        this.turnHistory = [];
        this.usedSignalantIds = new Set();
        this.homeX = typeof options.homeX === "number" ? options.homeX : x;
        this.homeY = typeof options.homeY === "number" ? options.homeY : y;
        this.distanceCheckpoints = [];
        this.carriedResourceKey = null;
        this.carriedResourceAmount = 0;
        this.carriedFoodValue = 0;
        this.carrySprite = null;

        this.setStats();

        antArray.push(this);
    }

    setStats() {
        if (this.initialStats) {
            this.stats = { ...this.initialStats };
            this.distanceRemaining = this.stats.maxTravelDistance;
            return;
        }

        loadAntById(`${this.color}_${this.type}`)
            .then(antData => {
                if (antData) {
                    this.stats = { ...antData.stats };
                    this.distanceRemaining = this.stats.maxTravelDistance;
                }
            });
    }

    update() {
        this.move();
        if (this.state === "outbound" && this.distanceRemaining <= 0) {
            this.startReturnTrip();
        }

        if (this.state === "returning" && this.returnDistanceRemaining <= 0) {
            this.despawn();
        }
    }

    startReturnTrip() {
        this.recordDistanceCheckpoint();
        this.state = "returning";
        this.returnDistanceRemaining = this.distanceTraveled;
        this.direction = normalizeDirection(this.direction + 180);
    }

    despawn() {
        totalStats.recordReturn(this.color);

        if (this.carriedFoodValue > 0) {
            currency.add(this.carriedFoodValue);
            totalStats.recordFoodLooted(this.color, this.carriedFoodValue, this.carriedResourceAmount);
            tutorial.trigger("resource.return");
        } else {
            totalStats.recordEmptyReturn(this.color);
        }

        totalStats.recordLongestTrip(this.color, this.distanceTraveled);
        totalStats.recordMaxDistance(this.color, this.getMaxRecordedDistanceFromHome());

        const index = antArray.indexOf(this);
        if (index !== -1) {
            antArray.splice(index, 1);
        }

        for (let signalant of signalantArray) {
            signalant.clearRelativeDirectionForAnt(this.id);
        }
    }

    recordDistanceCheckpoint() {
        this.distanceCheckpoints.push({ x: this.x, y: this.y });
    }

    getMaxRecordedDistanceFromHome() {
        if (this.distanceCheckpoints.length === 0) {
            return 0;
        }

        let maxDistance = 0;
        for (const checkpoint of this.distanceCheckpoints) {
            const dx = checkpoint.x - this.homeX;
            const dy = checkpoint.y - this.homeY;
            const distance = Math.sqrt(dx * dx + dy * dy);
            if (distance > maxDistance) {
                maxDistance = distance;
            }
        }

        return maxDistance;
    }

    move() {
        if (typeof this.stats?.speed !== 'number' || gameTime.scaledDeltaMs <= 0) {
            return;
        }

        const deltaTime = gameTime.scaledDeltaMs / 60;
        const moveDistance = this.stats.speed * deltaTime;

        if (this.state === "returning") {
            const traveledReturnDistance = Math.min(moveDistance, this.returnDistanceRemaining);
            this.moveAlongDirection(traveledReturnDistance);
            this.returnDistanceRemaining -= traveledReturnDistance;
            this.updateReturnDirection();
            return;
        }

        this.moveAlongDirection(moveDistance);
        this.distanceTraveled += moveDistance;
        this.distanceRemaining -= moveDistance;

        for (let signalant of signalantArray) {
            if (this.usedSignalantIds.has(signalant.id)) {
                continue;
            }

            const dx = signalant.x - this.x;
            const dy = signalant.y - this.y;
            const distanceSquared = dx * dx + dy * dy;
            const radius = signalant.affectionRadius;

            if (distanceSquared < radius * radius && signalant.affectsColors.includes(this.color)) {
                this.recordDistanceCheckpoint();
                this.turnHistory.push({
                    distanceAtTurn: this.distanceTraveled,
                    previousDirection: this.direction
                });

                const relativeDirection = signalant.getRelativeDirectionForAnt(this.color, this.id);
                this.direction = signalant.direction + relativeDirection;
                this.distanceRemaining = this.stats.maxTravelDistance;
                this.usedSignalantIds.add(signalant.id);
            }
        }

        resources.tryHarvestWithAnt(this);

    }

    isCarryingResource() {
        return this.carriedResourceAmount > 0;
    }

    collectResource(resource, amount) {
        this.carriedResourceKey = resource.resourceKey;
        this.carriedResourceAmount = amount;
        this.carriedFoodValue = amount * resource.value;
        this.carrySprite = loadSprite(resource.carrySpritePath);
        this.startReturnTrip();
    }

    drawCarryLayer(ctx, cam) {
        if (!this.carrySprite) {
            return;
        }

        const relativeX = Math.round((this.x + cam.x) * cam.zoom);
        const relativeY = Math.round((this.y + cam.y) * cam.zoom);
        const width = Math.round(this.width * cam.zoom);
        const height = Math.round(this.height * cam.zoom);

        ctx.save();
        ctx.translate(relativeX, relativeY);
        ctx.rotate(this.direction * Math.PI / 180);
        ctx.drawImage(this.carrySprite, -width / 2, -height / 2, width, height);
        ctx.restore();
    }

    draw(ctx, cam) {
        super.draw(ctx, cam);
        this.drawCarryLayer(ctx, cam);
    }

    moveAlongDirection(distance) {
        const radians = this.direction * Math.PI / 180;
        this.x += Math.cos(radians) * distance;
        this.y += Math.sin(radians) * distance;
    }

    updateReturnDirection() {
        while (this.turnHistory.length > 0) {
            const nextTurn = this.turnHistory[this.turnHistory.length - 1];
            if (this.returnDistanceRemaining > nextTurn.distanceAtTurn) {
                break;
            }

            this.direction = normalizeDirection(nextTurn.previousDirection + 180);
            this.turnHistory.pop();
        }
    }
}

export function updateAnts() {
    for (let index = antArray.length - 1; index >= 0; index--) {
        antArray[index].update();
    }
}

export function drawAnts(ctx, cam) {
    for (let ant of antArray) {
        ant.draw(ctx, cam);
    }
}