/*
<copyright file="BGDatabaseGetFieldA.cs" company="BansheeGz">
    Copyright (c) 2018-2021 All Rights Reserved
</copyright>
*/

using System;
using Bolt;
using Ludiq;

namespace BansheeGz.BGDatabase
{
    public abstract class BGDatabaseGetFieldA : Unit
    {
        public enum EntitySourceEnum
        {
            Index,
            Id,
            Name,
            Entity
        }

        [DoNotSerialize] public ValueInput metaName;
        [DoNotSerialize] public ValueInput fieldName;
        [DoNotSerialize] public ValueInput entitySource;
        [DoNotSerialize] public ValueInput entityIndex;
        [DoNotSerialize] public ValueInput entityId;
        [DoNotSerialize] public ValueInput entityName;
        [DoNotSerialize] public ValueInput entity;

        protected override void Definition()
        {
            metaName = ValueInput<string>("Meta name", "");
            fieldName = ValueInput<string>("Field name", "");
            entitySource = ValueInput<EntitySourceEnum>("Entity source", EntitySourceEnum.Index);
            entityIndex = ValueInput<int>("Entity index", -1);
            entityId = ValueInput<string>("Entity ID", "");
            entityName = ValueInput<string>("Entity name", "");
            entity = ValueInput<BGEntity>("Entity");

        }
        
                protected BGMetaEntity GetMeta(Flow flow)
        {
            var tableName = flow.GetValue<string>(metaName);
            if (string.IsNullOrEmpty(tableName)) throw new Exception("Meta name is not set!");
            var meta = BGRepo.I[tableName];
            if (meta == null) throw new Exception("Can not find meta with name " + tableName + "!");
            return meta;
        }

        protected BGField GetField(Flow flow, BGMetaEntity meta)
        {
            var tableFieldName = flow.GetValue<string>(fieldName);
            if (string.IsNullOrEmpty(tableFieldName)) throw new Exception("Field name is not set! meta=" + meta.Name);
            var field = meta.GetField(tableFieldName, false);
            if (field == null) throw new Exception("Can not find field with name " + tableFieldName + "! meta=" + meta.Name);
            return field;
        }

        protected BGEntity GetEntity(Flow flow, BGMetaEntity meta)
        {
            var entitySourceValue = flow.GetValue<EntitySourceEnum>(entitySource);
            BGEntity row;
            switch (entitySourceValue)
            {
                case EntitySourceEnum.Index:
                    var entityIndexValue = flow.GetValue<int>(entityIndex);
                    if (entityIndexValue < 0 || entityIndexValue >= meta.CountEntities)
                        throw new Exception("Can not get entity with index " + entityIndexValue +
                                            ": index less than 0 or more than entities count! meta=" + meta.Name + " index=" + entityIndexValue);
                    row = meta.GetEntity(entityIndexValue);
                    break;
                case EntitySourceEnum.Id:
                    var entityIdValue = flow.GetValue<string>(entityId);
                    var entityIdValueTyped = BGId.Parse(entityIdValue);
                    if (entityIdValueTyped.IsEmpty) throw new Exception("Can not get entity by ID: ID is not set or invalid! meta=" + meta.Name + " ID=" + entityIdValue);

                    row = meta.GetEntity(entityIdValueTyped);
                    if (row == null) throw new Exception("Can not get entity by ID: entity is not found! meta=" + meta.Name + " ID=" + entityIdValue);
                    break;
                case EntitySourceEnum.Name:
                    var entityNameValue = flow.GetValue<string>(entityName);
                    row = meta.GetEntity(entityNameValue);
                    if (row == null) throw new Exception("Can not get entity by name: entity is not found! meta=" + meta.Name + " name=" + entityNameValue);
                    break;
                case EntitySourceEnum.Entity:
                    row = flow.GetValue<BGEntity>(entity);
                    if (row == null) throw new Exception("Can not get entity: entity is not assigned! meta=" + meta.Name);
                    if (!Equals(row.Meta, meta)) throw new Exception("Provided entity does not belong to " + meta.Name + " table : The entity's meta is " + row.Meta.Name);
                    break;
                default:
                    throw new ArgumentOutOfRangeException("entitySourceValue");
            }

            return row;
        }

    }
}