using System;
using System.Collections.Generic;
using Unity.Collections;
using UnityEngine;
using UnityEngine.Serialization;
using Random = System.Random;

public class Mail {
    public int FromAddress;
    public int ToAddress;
    public double TimeExisted;
}

public class MailGenerator : MonoBehaviour {
    [FormerlySerializedAs("MailCycleTime")] [SerializeField] private int mailCycleTime = 5;
    [FormerlySerializedAs("MailChance")] [SerializeField, Range(0, 1)] private double mailChance = 0.2;
    [FormerlySerializedAs("MaxMail")] [SerializeField] private int maxMail = 10;
    [SerializeField, Range(0, 1)] private double mailAmountAdjustment = 0.3;
    [SerializeField] private bool mailAdjustment = true;
    [SerializeField] private int address;
    [SerializeField] private BuildingManager manager;
    [SerializeField] private double maxMailLifetime = 30;
    
    [FormerlySerializedAs("CurrentMail")] [SerializeField, ReadOnly] private int currentMail = 0;
    [FormerlySerializedAs("CycleTime")] [SerializeField, ReadOnly] private double cycleTime = 0.0;
    [FormerlySerializedAs("LastRandomMail")] [SerializeField, ReadOnly] private double lastRandomMail = 0.0;
    [FormerlySerializedAs("LastRandomCutoff")] [SerializeField, ReadOnly] private double lastRandomCutoff = 0.0;
    [SerializeField, ReadOnly] private double lastMailAmountAdjustment = 0.0;
    [SerializeField, ReadOnly] private double lastMailAmountAdjustedBy = 0.0;

    private Random _rng;
    private Dictionary<int, Mail> _mail;

    // Start is called before the first frame update
    private void Start() {
        _rng = new Random();
        _mail = new Dictionary<int, Mail>();
        
        manager.RegisterMailGenerator(address, this);
    }

    // Update is called once per frame
    private void Update() {
        cycleTime += Time.deltaTime;

        foreach (var mail in _mail) {
            mail.Value.TimeExisted += Time.deltaTime;

            if (mail.Value.TimeExisted > maxMailLifetime) {
                manager.GameOver(mail.Value.ToAddress);
            }
        }

        if (cycleTime > mailCycleTime) {
            cycleTime = 0;

            lastRandomMail = _rng.NextDouble();
            lastRandomCutoff = 1 - mailChance;
            
            if (currentMail < maxMail && lastRandomMail > lastRandomCutoff) {
                currentMail++;
                var newMail = new Mail {
                    FromAddress = address,
                    ToAddress = manager.RandomMailGeneratorNot(address),
                    TimeExisted = 0.0
                };
                _mail[currentMail] = newMail;
            }

            if (mailAdjustment) {
                lastMailAmountAdjustment = _rng.NextDouble() - 0.5;
                lastMailAmountAdjustedBy = lastMailAmountAdjustment * mailAmountAdjustment;
                mailChance += lastMailAmountAdjustedBy;
            }

            if (mailChance > 1) mailChance = 1;
            if (mailChance < 0) mailChance = 0;
        }
    }
}