using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using Kreta.Core;
using Kreta.DataAccess.Interfaces;
using Kreta.DataAccessManual.Extensions;
using Kreta.DataAccessManual.Interfaces;
using Kreta.DataAccessManual.ParameterClasses;
using Kreta.DataAccessManual.Util;
using Kreta.Enums;
using Kreta.Framework;
using Kreta.Framework.Util;
using SDA.DataProvider;
using SDA.Kreta.Entities;

namespace Kreta.DataAccessManual
{
    internal class IgazolasDal : DataAccessBase, IIgazolasDal
    {
        public IgazolasDal(DalHandler handler, GridParameters parameters) : base(handler, parameters)
        { }

        public IgazolasDal(DalHandler handler) : base(handler)
        { }

        public IIgazolas Get()
        {
            return Igazolas.GiveAnInstance();
        }

        public IIgazolas Get(int id)
        {
            var entity = Igazolas.GiveAnInstance();
            entity.LoadByID(id);
            return entity;
        }

        public void Insert(IIgazolas dto)
        {
            var entity = dto as Igazolas;
            entity.Insert();
            HandleIgazolasokAfterInsert(entity);
            dto.ID = entity.ID;

            DalHelper.Commit();
        }

        public void Update(IIgazolas dto)
        {
            if (dto is Igazolas entity)
            {
                HandleIgazolasokBeforeUpdate(entity);
                entity.Update();
                DalHelper.Commit();
            }
        }
        public void Delete(int id)
        {
            var entity = Igazolas.GiveAnInstance();
            entity.LoadByID(id);

            this.Delete(entity);
        }

        public void Delete(IIgazolas dto)
        {
            var entity = dto as Igazolas;
            var igazoltMulasztasIDk = DalHelper.MulasztasDal().GetTanuloIgazoltMulasztasIdoszakban(entity.TanuloId, entity.Kezdete, entity.Vege, entity.IgazolasTipusa).GetIdListFromFirstTable();

            entity.Delete();

            foreach (int mulasztasID in igazoltMulasztasIDk)
            {
                MulasztasIgazolasTorlese(mulasztasID);
            }

            DalHelper.Commit();
        }

        public DataSet GetIgazolasInfo(int igazolasId)
        {
            IgazolasokListajaSearchPCO pco = new IgazolasokListajaSearchPCO()
            {
                IgazolasId = igazolasId
            };
            return GetIgazolasokDataSet(pco, false);
        }

        public DataSet GetIgazolasDataSet(int tanuloId)
        {
            var pco = new IgazolasokListajaSearchPCO()
            {
                TanuloId = tanuloId
            };

            var ds = GetIgazolasokDataSet(pco, false, simpleResult: true);

            return ds;
        }

        public DataSet GetIgazolasSearchDataSet(IgazolasSearchPco pco)
        {
            var igazolasokListajaSearchPCO = new IgazolasokListajaSearchPCO()
            {
                IgazolasKezdteteSearch = pco.IgazolasKezdeteSearch,
                IgazolasVegeSearch = pco.IgazolasVegeSearch,
                IgazolasTipusaSearch = pco.IgazolasTipusaSearch,
                TanuloId = pco.TanuloId,
                FeladatEllatasiHelyId = pco.FeladatEllatasiHelyId,
                FeladatKategoriaId = pco.FeladatKategoriaId
            };

            var ds = GetIgazolasokDataSet(igazolasokListajaSearchPCO, false, simpleResult: true);

            return ds;
        }

        public DataSet GetIgazolasExcelExport(IgazolasokListajaSearchPCO pco)
        {
            return GetIgazolasokDataSet(pco, false, isExcelExport: true);
        }

        public DataSet GetOsztalyCsoportIgazolasokForValidate(DataTable igazolasDT)
        {
            if (igazolasDT.Rows.Count > 0)
            {
                string CommandText = @"
                    SELECT
                        C_TANULOID AS TanuloId,
                        C_KEZDETE AS ElsoNap,
                        C_VEGE AS UtolsoNap
                    FROM T_IGAZOLAS_OSSZES
                    WHERE ";
                for (int i = 0; i < igazolasDT.Rows.Count; i++)
                {
                    CommandText += @"((C_KEZDETE <= '" + igazolasDT.Rows[i]["UtolsoNap"] + @"' AND C_VEGE >= '" + igazolasDT.Rows[i]["ElsoNap"] + @"') AND C_TANULOID = " + igazolasDT.Rows[i]["TanuloId"] + " AND ISNULL(C_SZERVEZETID,0) = ISNULL(" + igazolasDT.Rows[i]["SzervezetId"] + ",0)) ";
                    if (i != igazolasDT.Rows.Count - 1)
                        CommandText += " OR ";
                }

                CommandText += " AND C_TANEVID = :pTANEVID AND C_INTEZMENYID = :pINTEZMENYID AND TOROLT = 'F'";
                var parameters = new List<CommandParameter> { new CommandParameter("pTANEVID", igazolasDT.Rows[0]["TanevId"]), new CommandParameter("pINTEZMENYID", igazolasDT.Rows[0]["IntezmenyId"]) };
                DataSet ds = GetData(CommandText, parameters);
                return ds;
            }

            return new DataSet();
        }

        public DataSet GetIgazolasokByDate(DateTime date, int tanevId, int intezmenyId)
        {
            string CommandText = @"
                    SELECT
                        C_TANULOID AS TanuloId,
                        C_IGAZOLASTIPUSA AS Tipus
                    FROM T_IGAZOLAS_OSSZES
                    WHERE C_KEZDETE <= :pDate AND C_VEGE >= :pDate
                    AND C_TANEVID = :pTANEVID AND C_INTEZMENYID = :pINTEZMENYID AND TOROLT = 'F'
                ";

            var parameters = new List<CommandParameter> {
                    new CommandParameter("pDate", date.Date),
                    new CommandParameter("pTANEVID", tanevId),
                    new CommandParameter("pINTEZMENYID", intezmenyId)
                };

            DataSet ds = GetData(CommandText, parameters);
            return ds;
        }

        public DataSet GetOsztalyCsoportIgazolasok(int osztalyCsoportId, OktNevelesiKategoriaEnum? feladatKategoria)
        {
            var pco = new IgazolasokListajaSearchPCO()
            {
                OsztalyCsoportSearch = osztalyCsoportId,
                FeladatKategoriaId = (int?)feladatKategoria
            };
            var ds = GetIgazolasokDataSet(pco, false);
            return ds;
        }

        public DataSet GetMulasztasLehetsegesIgazolasai(int mulasztasID)
        {
            string CommandText = @"
                SELECT
                    T_IGAZOLAS.ID ID,
                    T_IGAZOLAS.C_IGAZOLASTIPUSA Tipus

                FROM T_IGAZOLAS

                    INNER JOIN T_TANULOMULASZTAS
                        ON T_TANULOMULASZTAS.C_ORATANULOIID = T_IGAZOLAS.C_TANULOID
                    INNER JOIN T_TANITASIORA
                        ON T_TANULOMULASZTAS.C_TANITASIORAKID = T_TANITASIORA.ID
                            AND T_TANITASIORA.C_DATUM >= T_IGAZOLAS.C_KEZDETE
                            AND T_TANITASIORA.C_DATUM <= T_IGAZOLAS.C_VEGE

                WHERE T_IGAZOLAS.TOROLT='F'
                    AND T_TANULOMULASZTAS.ID = :pMulasztasID";

            var param = new List<CommandParameter> { new CommandParameter("pMulasztasID", mulasztasID) };
            DataSet ds = GetData(CommandText, param);
            return ds;
        }

        public DataSet IgazolasKereses(int? osztCsopId, OktNevelesiKategoriaEnum? feladatKategoria, int? szervezetTipusId = null)
        {
            List<CommandParameter> paramsList = new List<CommandParameter>();
            if (feladatKategoria.HasValue)
            { paramsList.Add(new CommandParameter("OktNevKatTipus", (int)feladatKategoria)); }
            else
            { paramsList.Add(new CommandParameter("OktNevKatTipus", DBNull.Value)); }

            StringBuilder command = new StringBuilder(@"
                SELECT DISTINCT
                     f.ID as ID
                    ,f.C_NYOMTATASINEV as TanuloNev
                    ,IIF(f.C_NEVSORREND = 'T',
                         f.C_UTONEV + ' ' + f.C_VEZETEKNEV,
                         f.C_VEZETEKNEV + ' ' + f.C_UTONEV) as TanuloNevElotagNelkul
                    ,1530 as IgazolasTipus
                    ,ocs.C_NEV AS OsztCsopNev
                    ,f.C_ANYJANEVE AS AnyjaNeve
                    ,FORMAT(f.C_SZULETESIDATUM, 'yyyy. MM. dd.') AS SzuletesiIdo 
                " + (szervezetTipusId.HasValue ? @",(SELECT TOP 1 tta.C_SZERVEZETID 
                        FROM T_TANULOCSOPORT_OSSZES tcs
                        INNER JOIN T_TANULOTANUGYIADATOK_OSSZES tta ON tta.C_TANULOCSOPORTID = tcs.ID AND tta.TOROLT = 'F' AND tta.C_SZERVEZETID IS NOT NULL
                        WHERE tcs.C_TANULOID = f.ID AND(tcs.C_KILEPESDATUM IS NULL OR tcs.C_KILEPESDATUM > GETDATE()) AND tcs.C_BELEPESDATUM <= GETDATE()) as TanuloSzervezetId" : "") + @"
                FROM T_OSZTALYCSOPORT ocs
                    JOIN T_TANULOCSOPORT tcs ON tcs.C_OSZTALYCSOPORTID = ocs.ID AND tcs.TOROLT = 'F'
                    JOIN T_FELHASZNALO f ON f.ID = tcs.C_TANULOID AND f.TOROLT = 'F'
                where
                    ocs.TOROLT = 'F'
                    AND (ocs.C_FELADATKATEGORIAID = @OktNevKatTipus OR @OktNevKatTipus IS NULL) ");

            if (osztCsopId.HasValue && osztCsopId.Value > 0)
            {
                command.Append(@" AND ocs.ID = :pOsztCsopId ");
                paramsList.Add(new CommandParameter("pOsztCsopId", osztCsopId));
            }
            else
            {
                command.Append(@" AND ocs.ID = :pOsztCsopId ");
                paramsList.Add(new CommandParameter("pOsztCsopId", -1));
            }

            return this.GetData(command.ToString(), paramsList);
        }

        public DataSet IgazolasDetailKereses(int tanuloId, int? szervezetTipusId = null)
        {
            var pco = new IgazolasokListajaSearchPCO()
            {
                TanuloId = tanuloId
            };

            var ds = GetIgazolasokDataSet(pco, false, simpleResult: true, szervezetTipusId: szervezetTipusId);
            return ds;
        }

        /// INFO @DevKornel: Mobil használja
        public DataSet GetIgazolasokListajaGrid(IgazolasokListajaSearchPCO pco, OktNevelesiKategoriaEnum? feladatKategoria)
        {
            pco.FeladatKategoriaId = (int?)feladatKategoria ?? pco.FeladatKategoriaId;
            return GetIgazolasokDataSet(pco, true, isExcelExport: true);
        }

        /// <summary>
        /// A szűrőparaméterek alapján SP használatával lekérdezi az Igazolasok DataSet-et!
        /// </summary>
        /// <param name="pco">Szűrő paraméterek</param>
        /// <param name="needPaging">Szükség van-e lapozáásra az SP-ben</param>
        /// <param name="isExcelExport">ExcelExport-hoz fut-e a lekérdezés</param>
        /// <returns></returns>
        /// INFO @DevKornel: Mobil használja
        private DataSet GetIgazolasokDataSet(IgazolasokListajaSearchPCO pco, bool needPaging, bool simpleResult = false, bool isExcelExport = false, int? szervezetTipusId = null)
        {
            var parameters = SetParametersForIgazolasokSearch(pco);
            using (var cmd = new SDACommand())
            {
                cmd.Connection = UserContext.Instance.SDAConnection;
                cmd.Transaction = UserContext.Instance.SDATransaction;
                cmd.CommandType = CommandType.StoredProcedure;

                cmd.CommandText = "uspGetIgazolasInfo";

                foreach (var param in parameters)
                {
                    cmd.Parameters.Add(param.Name, param.Value);
                }

                if (isExcelExport)
                {
                    cmd.Parameters.Add("IsExport", true);
                }

                if (simpleResult)
                {
                    cmd.Parameters.Add("SimpleResult", true);
                }

                if(szervezetTipusId.HasValue)
                {
                    cmd.Parameters.Add("pSzervezetTipusId", szervezetTipusId.Value);
                }
                
                var ds = new DataSet();
                using (var adapter = new SDADataAdapter())
                {
                    adapter.SelectCommand = cmd;
                    adapter.Fill(ds);
                }
                SetDNAME(ds.Tables[0], "IgazolasTipusa");

                if (needPaging || GridParameters != null)
                {
                    return SortingAndPaging(ds.Tables[0], GridParameters).AsDataSet();
                }

                return ds;
            }
        }

        /// <summary>
        /// Keresési feltételek összeállítása az SP részére. A paraméternevek az SP-ben lévőkkel kell, hogy egyezzenek!
        /// </summary>
        private List<CommandParameter> SetParametersForIgazolasokSearch(IgazolasokListajaSearchPCO pco)
        {
            var parameters = new List<CommandParameter>();

            if (pco.FeladatKategoriaId.IsEntityId())
            {
                parameters.Add(new CommandParameter("pFeladatKategoriaId", pco.FeladatKategoriaId.Value));
            }

            if (pco.FeladatEllatasiHelyId.IsEntityId())
            {
                parameters.Add(new CommandParameter("pFeladatEllatasiHelyId", pco.FeladatEllatasiHelyId.Value));
            }

            if (pco.IgazolasId.HasValue && pco.IgazolasId.Value > 0)
            {
                parameters.Add(new CommandParameter("pIgazolasId", pco.IgazolasId.Value));
            }

            if (pco.IntezmenyId > 0)
            {
                parameters.Add(new CommandParameter("pIntezmenyId", pco.IntezmenyId));
            }

            if (pco.TanevId.IsEntityId())
            {
                parameters.Add(new CommandParameter("pTanevId", pco.TanevId.Value));
            }

            if (pco.TanuloId.HasValue && pco.TanuloId.Value > 0)
            {
                parameters.Add(new CommandParameter("pTanuloId", pco.TanuloId.Value));
            }

            if (pco.IgazolasKezdteteSearch.HasValue)
            {
                parameters.Add(new CommandParameter("pIgazolasKezdete", pco.IgazolasKezdteteSearch.Value));
            }

            if (pco.IgazolasVegeSearch.HasValue)
            {
                parameters.Add(new CommandParameter("pIgazolasVege", pco.IgazolasVegeSearch.Value));
            }

            if (pco.IgazolasTipusaSearch.HasValue)
            {
                parameters.Add(new CommandParameter("pIgazolasTipusa", pco.IgazolasTipusaSearch.Value));
            }

            if (!string.IsNullOrWhiteSpace(pco.NevSearch))
            {
                parameters.Add(new CommandParameter("pTanuloNeve", pco.NevSearch));
            }

            if (pco.OsztalyCsoportSearch.HasValue)
            {
                parameters.Add(new CommandParameter("pOsztalyCsoportId", pco.OsztalyCsoportSearch.Value));
            }

            if (pco.RogzitesDatumaIgSearch.HasValue)
            {
                parameters.Add(new CommandParameter("pRogzitesDatumaIg", pco.RogzitesDatumaIgSearch.Value));
            }

            if (pco.RogzitesDatumaTolSearch.HasValue)
            {
                parameters.Add(new CommandParameter("pRogzitesDatumaTol", pco.RogzitesDatumaTolSearch.Value));
            }

            if (pco.RogzitoSearch.HasValue && pco.RogzitoSearch.Value > 0)
            {
                parameters.Add(new CommandParameter("pRogzitoId", pco.RogzitoSearch.Value));
            }

            if (pco.IgazolasDatuma.HasValue)
            {
                parameters.Add(new CommandParameter("pIgazolasDatuma", pco.IgazolasDatuma.Value));
            }

            return parameters;
        }

        private void MulasztasIgazolasTorlese(int mulasztasID, int? kiveve = null)
        {
            TanuloMulasztas mulasztas = TanuloMulasztas.GiveAnInstance();
            mulasztas.LoadByID(mulasztasID);
            DataSet ds = GetMulasztasLehetsegesIgazolasai(mulasztasID);

            if (kiveve.HasValue)
            {
                for (int i = ds.Tables[0].Rows.Count - 1; i >= 0; i--)
                {
                    DataRow dr = ds.Tables[0].Rows[i];
                    if (Convert.ToInt32(dr["ID"]) == kiveve)
                        dr.Delete();
                }
                ds.AcceptChanges();
            }

            //Ha létezik olyan igazolás, amelyik az adott mulasztást igazolhatja, akkor nem törlünk, csak a típust írjuk felül
            if (ds.Tables[0].Rows.Count > 0)
            {
                mulasztas.IgazolasTipusa = Convert.ToInt32(ds.Tables[0].Rows[0]["Tipus"]);
            }
            else
            {
                mulasztas.Igazolt = null;
                //mulasztas.Igazolt = false;
                mulasztas.IgazolasTipusa = null;
            }
            mulasztas.Update();
        }

        private void MulasztasIgazolasa(int tanevId, int mulasztasID, int tipus)
        {
            var mulasztas = TanuloMulasztas.GiveAnInstance();
            mulasztas.LoadByID(mulasztasID);
            var needJuttatasUpdate = mulasztas.Igazolt.HasValue && !mulasztas.Igazolt.Value;
            mulasztas.Igazolt = true;
            mulasztas.IgazolasTipusa = tipus;
            mulasztas.Update();
            if ((mulasztas.Intezmeny.IntezmenyAdatok.SingleOrDefault(x => !x.Torolt && x.TanevId == mulasztas.TanevId)?.IsSzakkepzoJuttatas ?? false) && needJuttatasUpdate)
            {
                var dal = DalHelper.JuttatasDAL();
                dal.UpdateTanulokSzakkepzesiJuttatasok(tanevId, mulasztas.EntityModifier.Value, (int)JuttatasTipusEnum.szakkepzesi_juttatas, tanuloId: mulasztas.OraTanuloiId);
                dal.UpdateTanulokSzakkepzesiJuttatasok(tanevId, mulasztas.EntityModifier.Value, (int)JuttatasTipusEnum.apaczaiosztondij, tanuloId: mulasztas.OraTanuloiId);
            }
        }

        private void HandleIgazolasokBeforeUpdate(Igazolas entity)
        {
            DateTime kezdete = Convert.ToDateTime(entity.GetOriginalValue("Kezdete"));
            DateTime vege = Convert.ToDateTime(entity.GetOriginalValue("Vege"));
            int tanuloId = Convert.ToInt32(entity.GetOriginalValue("TanuloId"));
            int tipus = Convert.ToInt32(entity.GetOriginalValue("IgazolasTipusa"));

            var igazoltMulasztasIDk = DalHelper.MulasztasDal().GetTanuloIgazoltMulasztasIdoszakban(tanuloId, kezdete, vege, tipus).GetIdListFromFirstTable();

            foreach (int mulasztasID in igazoltMulasztasIDk)
            {
                MulasztasIgazolasTorlese(mulasztasID, kiveve: entity.ID);
            }

            var igazolatlanMulasztasIDk = DalHelper.MulasztasDal().GetTanuloIgazolatlanMulasztasIdoszakban(entity.TanuloId, entity.Kezdete, entity.Vege).GetIdListFromFirstTable();
            foreach (int mulasztasID in igazolatlanMulasztasIDk)
            {
                MulasztasIgazolasa(entity.TanevId, mulasztasID, entity.IgazolasTipusa);
            }
        }

        private void HandleIgazolasokAfterInsert(Igazolas entity)
        {
            List<int> igazolatlanMulasztasIDk = DalHelper.MulasztasDal().GetTanuloIgazolatlanMulasztasIdoszakban(entity.TanuloId, entity.Kezdete, entity.Vege).GetIdListFromFirstTable();

            foreach (int mulasztasID in igazolatlanMulasztasIDk)
            {
                MulasztasIgazolasa(entity.TanevId, mulasztasID, entity.IgazolasTipusa);
            }
        }
    }
}