using Project;
using Project.Device;
using Project.StateMachine;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Management;
using System.Net;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading.Tasks;

/// <summary>
/// ============================================================================
/// 장비기술 상태 모니터링 관련 클래스
/// 이 클래스는 SQLfiletoDB 프로그램과 같이 사용하는 것을 권장합니다.
/// 현재 실행 중인 프로그램의 하위 폴더 Status 에 입력된 상태값을 SQL 파일로 기록합니다.
/// SQLfiletoDB는 SQL파일을 실제 DB에 기록하는 프로그램입니다.
/// ============================================================================
/// 작성자 : chi
/// 작성일 : 202-06-15
/// GIT : (none)
/// </summary>
public static partial class EEMStatus
{
    static System.Threading.ManualResetEvent mre = new System.Threading.ManualResetEvent(true);
    static string ip = string.Empty;
    static string mac = string.Empty;
    static DateTime StatusChecktime = DateTime.Now;
    static DateTime MonitorChecktime = DateTime.Now.AddYears(-1);
    static DateTime FileCheckTime = DateTime.Now;
    static string monitorfile = string.Empty;
    /// <summary>
    /// UpdateStatusSQL 명령이 동작하는 간격이며 기본 180초(=3분)로 되어 있습니다.
    /// </summary>
    public static int UpdateStatusInterval { get; set; } = 180;
    public static int UpdateFileInterval { get; set; } = 3;
    static bool queryok = false;
    static bool UpdateRun = false;

    public static string IP
    {
        get
        {
            if (queryok == false) GetNetworkInfo();
            return ip;
        }
        set { ip = value; }
    }
    public static string MAC
    {
        get
        {
            if (queryok == false) GetNetworkInfo();
            return mac;
        }
        set
        {
            mac = value;
        }
    }

    /// <summary>
    /// 현재 시스템의 IP/MAC정보를 취득합니다.
    /// </summary>
    static void GetNetworkInfo()
    {

        ip = "";
        mac = "";
        //      string prgmName = Application.ProductName;

        var nif = NetworkInterface.GetAllNetworkInterfaces();
        var host = Dns.GetHostEntry(Dns.GetHostName());
        string fullname = System.Net.Dns.GetHostEntry("").HostName;
        foreach (IPAddress r in host.AddressList)
        {
            string str = r.ToString();

            if (str != "" && str.Substring(0, 3) == "10.")
            {
                ip = str;
                break;
            }
        }

        string rtn = string.Empty;
        ObjectQuery oq = new System.Management.ObjectQuery("SELECT * FROM Win32_NetworkAdapterConfiguration WHERE IPEnabled='TRUE'");
        ManagementObjectSearcher query1 = new ManagementObjectSearcher(oq);
        foreach (ManagementObject mo in query1.Get())
        {
            string[] address = (string[])mo["IPAddress"];
            if (address[0] == ip && mo["MACAddress"] != null)
            {
                mac = mo["MACAddress"].ToString();
                break;
            }
        }
        queryok = true;
    }

    /// <summary>
    /// 배터리데이터수신시 값을 기록한다.
    /// </summary>
    public static void MakeBMSInformation_INFO()
    {
        if (PUB.BMS.Current_DataTime.Year == 1982 || LastBMSIFTime == PUB.BMS.Current_DataTime || PUB.setting.MCID.isEmpty()) return;
        try
        {
            // BMS 데이터 취득 (실제 BMS 객체에서 데이터를 가져와야 함)
            // 예시: var bms = Project.Device.BMS.Instance;
            var mcid = Project.PUB.setting.MCID;
            var timestr = PUB.BMS.Current_DataTime.ToString("yyyy-MM-dd HH:mm:ss");

            var data = PUB.BMS.BMSInformation;
           
            // Status 폴더에 SQL 파일 생성
            var path = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Status");
            if (System.IO.Directory.Exists(path) == false)
                System.IO.Directory.CreateDirectory(path);

            var file = System.IO.Path.Combine(path, $"{DateTime.Now.ToString("HHmmssfff")}_BMS_INF.sql");

            var sql = "insert into AGV_Shuttle_BMS(MCID,wdate,info_volt,info_current,info_capa,info_level,info_temp1,info_temp2,soc,cycle,protection,balance,watt) " +
                     $"values('{mcid}','{timestr}',{data.packVoltage},{data.current},{data.fullCapacity},{data.RawLevel},{data.ntcTemp[0]},{data.ntcTemp[1]},{data.rsoc},{data.cycleCount},{data.raw_protection},{data.fullBalance},{data.watt})";

            System.IO.File.WriteAllText(file, sql, System.Text.Encoding.Default);
            LastBMSIFTime = DateTime.Now;
        }
        catch (Exception ex)
        {
            // 오류 로깅 (필요시 PUB.log.Add 등으로 처리)
            Console.WriteLine($"MakeBMSInformation Error: {ex.Message}");
        }
    }

    static DateTime LastBMSIFTime = DateTime.Now;
    static DateTime LastBMSCVTime = DateTime.Now;

    /// <summary>
    /// 배터리데이터수신시 값을 기록한다.
    /// </summary>
    public static void MakeBMSInformation_Cell()
    {
        if (PUB.BMS.Current_CellTime.Year == 1982 || LastBMSCVTime == PUB.BMS.Current_CellTime || PUB.setting.MCID.isEmpty()) return;
        try
        {
            // BMS 데이터 취득 (실제 BMS 객체에서 데이터를 가져와야 함)
            // 예시: var bms = Project.Device.BMS.Instance;
            var mcid = Project.PUB.setting.MCID;
            var timestr = PUB.BMS.Current_CellTime.ToString("yyyy-MM-dd HH:mm:ss");

            // BMS 데이터 (실제 값으로 교체 필요)
            var volt = PUB.BMS.BMSCellVoltage;
            var cell_volt1 = volt.Voltage[0];// "null"; // bms.CellVolt1
            var cell_volt2 = volt.Voltage[1]; // bms.CellVolt2
            var cell_volt3 = volt.Voltage[2]; // bms.CellVolt3
            var cell_volt4 = volt.Voltage[3]; // bms.CellVolt4
            var cell_volt5 = volt.Voltage[4]; // bms.CellVolt5
            var cell_volt6 = volt.Voltage[5]; // bms.CellVolt6
            var cell_volt7 = volt.Voltage[6]; // bms.CellVolt7
            var cell_volt8 = volt.Voltage[7]; // bms.CellVolt8

            // Status 폴더에 SQL 파일 생성
            var path = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Status");
            if (System.IO.Directory.Exists(path) == false)
                System.IO.Directory.CreateDirectory(path);

            var file = System.IO.Path.Combine(path, $"{DateTime.Now.ToString("HHmmssfff")}_BMS_CV.sql");

            var sql = "insert into AGV_Shuttle_BMS(MCID,wdate," +
                     "cell_volt1,cell_volt2,cell_volt3,cell_volt4,cell_volt5,cell_volt6,cell_volt7,cell_volt8) " +
                     "values('{0}','{1}',{2},{3},{4},{5},{6},{7},{8},{9})";

            sql = string.Format(sql, mcid, timestr,
                               cell_volt1, cell_volt2, cell_volt3, cell_volt4,
                               cell_volt5, cell_volt6, cell_volt7, cell_volt8);

            System.IO.File.WriteAllText(file, sql, System.Text.Encoding.Default);
            LastBMSCVTime = DateTime.Now;
        }
        catch (Exception ex)
        {
            // 오류 로깅 (필요시 PUB.log.Add 등으로 처리)
            Console.WriteLine($"MakeBMSInformation Error: {ex.Message}");
        }
    }

    public static void UpdateStatusSQL(eSMStep status, bool _extrun = false, string remark = "")
    {
        var tsrun = DateTime.Now - StatusChecktime;
        if (tsrun.TotalSeconds >= UpdateStatusInterval)
        {
            AddStatusSQL(status, "UPDATE", extrun: _extrun);
            StatusChecktime = DateTime.Now;
        }

        ////내부실행모드일때에만 파일을 처리한다
        //if (_extrun == false)
        //{
        //    var tsfile = DateTime.Now - FileCheckTime;
        //    if (tsfile.TotalSeconds >= UpdateFileInterval)
        //    {
        //        if (UpdateRun == false)
        //        {
        //            UpdateRun = true;
        //            Task.Run(() =>
        //            {
        //                UpdateFileToDB();
        //                UpdateRun = false;
        //            });
        //        }
        //        FileCheckTime = DateTime.Now;
        //    }
        //}
    }

    /// <summary>
    /// 상태모니터링 프로그램의 실행파일 명
    /// </summary>
    static string StatusMonitorFile
    {
        get
        {
            if (string.IsNullOrEmpty(monitorfile))
                monitorfile = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Status", "SQLFileToDB.exe");
            return monitorfile;
        }
    }

    static System.Diagnostics.Process CheckMonitor()
    {
        if (System.IO.File.Exists(StatusMonitorFile) == false) return null;

        var prcs = System.Diagnostics.Process.GetProcesses();
        return prcs.Where(t => t.ProcessName.ToLower().StartsWith("sqlfiletodb")).FirstOrDefault();
    }

    public static bool RunStatusMonitor()
    {
        //파일이 없으면 실행 불가
        if (System.IO.File.Exists(StatusMonitorFile) == false) return false;

        //실행프로세스 검사
        var prc = CheckMonitor();
        if (prc == null)
        {
            try
            {
                prc = new System.Diagnostics.Process();
                prc.StartInfo = new System.Diagnostics.ProcessStartInfo
                {
                    Arguments = string.Empty,
                    FileName = StatusMonitorFile,
                };
                prc.Start();
            }
            catch
            {
                return false;
            }
        }

        return true;
    }

    /// <summary>
    /// 작업수량을 입력합니다
    /// </summary>
    /// <param name="cnt"></param>
    /// <returns></returns>
    public static string AddStatusCount(int cnt, string remark = "")
    {
        if (remark.isEmpty()) remark = $"Count Set : {cnt}";
        return AddStatusSQL(PUB.sm.Step, remark, count: cnt);
    }
    /// <summary>
    /// 상태메세지를 status 폴더에 기록합니다.
    /// </summary>
    /// <param name="status">상태머신의 상태값</param>
    /// <param name="remark">비고</param>
    /// <param name="wdate">기록일시</param>
    /// <returns>오류발생시 오류메세지가 반환 됩니다</returns>
    public static string AddStatusSQL(eSMStep status, string remark = "", DateTime? wdate = null, bool extrun = false, int? count = null)
    {
        if (queryok == false || MAC.isEmpty()) GetNetworkInfo();
        if (status == eSMStep.CLOSEWAIT || status == eSMStep.CLOSED) return string.Empty;

        if (extrun)
        {
            //상태모니터링 프로그램을 실행합니다.
            var tsMon = DateTime.Now - MonitorChecktime;
            if (tsMon.TotalMinutes > 5) RunStatusMonitor();
        }

        try
        {
            var state = 0;
            string cntstr = "null";
            if (count != null) cntstr = count.ToString();
            var alarmid = string.Empty;
            var alarmmsg = string.Empty;
            if (string.IsNullOrEmpty(remark)) remark = $"STS:{status}";

            if (status == eSMStep.RUN) state = 1;
            else if (status == eSMStep.ERROR || status == eSMStep.EMERGENCY)
            {
                state = 2;
                alarmid = PUB.Result.ResultErrorCode.ToString();
                alarmmsg = PUB.Result.ResultMessage;
            }
            else if (status == eSMStep.PAUSE)   //일시중지도 오류코드가 포함된다, 
            {
                if (PUB.Result.ResultErrorCode == eECode.USER_STEP || PUB.Result.ResultErrorCode == eECode.USER_STOP || PUB.Result.ResultErrorCode.ToString().StartsWith("MESSAGE"))
                {
                    //사용자에의해 멈추는 것은 오류코드를 넣지 않는다.
                }
                else
                {
                    alarmid = PUB.Result.ResultErrorCode.ToString();
                    alarmmsg = PUB.Result.ResultMessage;
                }
            }
            else if (status == eSMStep.INIT) state = 3; //시작
            else if (status == eSMStep.CLOSING) state = 4;    //종료

            //length  check
            if (alarmid.Length > 10) alarmid = alarmid.Substring(0, 10);
            if (remark.Length > 99) remark = remark.Substring(0, 99);
            if (alarmmsg.Length > 250) alarmmsg = alarmmsg.Substring(0, 50);

            var mcid = Project.PUB.setting.MCID;//.Data.MCID;
            var path = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Status");
            var file = System.IO.Path.Combine(path, $"{DateTime.Now.ToString("HHmmssfff")}_{status}.sql");
            var sql = "insert into MCMonitor_Rawdata(Model,status,remark,ip,mac,time,alarmid,alarmmsg,count,version) " +
                " values('{0}','{1}','{2}','{3}','{4}','{5}','{6}','{7}',{8},'{9}')";

            var timestr = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
            if (wdate != null) timestr = ((DateTime)wdate).ToString("yyyy-MM-dd HH:mm:ss");
            var VersionNumber = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
            sql = string.Format(sql, mcid, state, remark.Replace("'", "''"), IP, MAC, timestr, alarmid, alarmmsg, cntstr, VersionNumber);
            System.IO.File.WriteAllText(file, sql, System.Text.Encoding.Default);

            ////만들어진지 3분이 지난 파일은 삭제한다.
            //var di = new System.IO.DirectoryInfo(path);
            //var fi = di.GetFiles("*.sql", System.IO.SearchOption.TopDirectoryOnly).Where(t => t.LastWriteTime < DateTime.Now.AddMinutes(-3)).FirstOrDefault();
            //if (fi != null) fi.Delete();
            //if (state == 4 && extrun == false) UpdateFileToDB();
            return string.Empty;
        }
        catch (Exception ex)
        {
            return ex.Message;
        }
    }



    //static void UpdateFileToDB()
    //{
    //    if (mre.WaitOne(1000) == false) return;
    //    mre.Reset();
    //    var cs = "Data Source=10.131.15.18;Initial Catalog=EE;Persist Security Info=True;User ID=eeuser;Password=Amkor123!";
    //    var path = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Status");
    //    var di = new System.IO.DirectoryInfo(path);
    //    if (di.Exists == false) return;
    //    var file = di.GetFiles("*.sql", System.IO.SearchOption.TopDirectoryOnly)
    //        .Where(t => t.LastWriteTime < DateTime.Now.AddSeconds(-3))
    //        .OrderByDescending(t => t.LastWriteTime).FirstOrDefault();

    //    if (file == null)
    //    {
    //        mre.Set();
    //        return;
    //    }

    //    //파일을 찾아야한다
    //    // PUB.log.Add($">> {file.FullName}");



    //    try
    //    {
    //        var sql = System.IO.File.ReadAllText(file.FullName, System.Text.Encoding.Default);
    //        if (string.IsNullOrEmpty(sql))
    //        {
    //            //비어잇다면
    //            var errpath = System.IO.Path.Combine(di.FullName, "Error");
    //            var errfile = System.IO.Path.Combine(errpath, file.Name);
    //            if (System.IO.Directory.Exists(errpath) == false) System.IO.Directory.CreateDirectory(errpath);
    //            System.IO.File.Move(file.FullName, errfile);// file.MoveTo(errfile);
    //            // ecnt += 1;
    //        }
    //        else
    //        {
    //            // var csstr = PUB.setting.ConnectionString;
    //            // if (string.IsNullOrEmpty(csstr)) csstr = "Data Source=10.131.15.18;Initial Catalog=EE;Persist Security Info=True;User ID=eeuser;Password=Amkor123!";
    //            var cn = new System.Data.SqlClient.SqlConnection(cs);
    //            var cmd = new System.Data.SqlClient.SqlCommand(sql, cn);
    //            cn.Open();
    //            var cnt = cmd.ExecuteNonQuery();
    //            //if (cnt == 0) PUB.log.Add($"Result Empty : {sql}");
    //            cn.Close();
    //            cnt += 1;

    //            var errpath = System.IO.Path.Combine(di.FullName, "Complete");
    //            var errfile = System.IO.Path.Combine(errpath, file.Name);
    //            if (System.IO.Directory.Exists(errpath) == false) System.IO.Directory.CreateDirectory(errpath);
    //            //file.MoveTo(errfile);
    //            System.IO.File.Move(file.FullName, errfile);
    //        }

    //    }
    //    catch (Exception ex)
    //    {
    //        var errpath = System.IO.Path.Combine(di.FullName, "Error");
    //        var errfile = System.IO.Path.Combine(errpath, file.Name);
    //        if (System.IO.Directory.Exists(errpath) == false) System.IO.Directory.CreateDirectory(errpath);
    //        try
    //        {
    //            //file.MoveTo(errfile);
    //            System.IO.File.Move(file.FullName, errfile);
    //        }
    //        catch (Exception ex2)
    //        {
    //            Console.WriteLine($"move error : {ex2.Message} : {errfile}");
    //        }

    //        //ecnt += 1;
    //    }

    //    try
    //    {
    //        //생성된지 10일이 넘은 자료는 삭제한다.
    //        //시간소비를 피해서 1개의 파일만 작업한다
    //        var sqlfiles = di.GetFiles("*.sql", System.IO.SearchOption.AllDirectories);
    //        //총3번의 데이터를 처리한다
    //        var files = sqlfiles.Where(t => t.LastWriteTime < DateTime.Now.AddDays(-10)).Select(t => t.FullName);
    //        int i = 0;
    //        var dellist = files.TakeWhile(t => i++ < 3);
    //        foreach (var delfile in dellist)
    //            System.IO.File.Delete(delfile);
    //    }
    //    catch
    //    {

    //    }
    //    mre.Set();
    //}
}


/*
=================================================
변경내역
=================================================
230619  chi UpdateFileToDB 에서 폴더가 없다면 return 하도록 함
230615  chi UpdateFiletoDB의 ManualResetEvent적용
            Version 항목 추가
230612  chi 프로그램 시작/종료 alarmid항목 추가
            완료된 파일 10일간 보존하도록 함
230522  chi extrun 모드 추가(agv용 - SQL파일을 외부 프로그램에서 처리하도록 함)
230617  chi 파일쓰기함수를 Task 로 처리
            3분지난데이터 삭제기능 제거
230516  chi initial commit
*/
