using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;

namespace Project.Web
{
    /// <summary>
    /// GroupWare WebSocket 서버
    /// npm run dev 환경에서 핫 리로드 개발을 위한 WebSocket 통신 지원
    /// </summary>
    public class WebSocketServer
    {
        private HttpListener _httpListener;
        private List<WebSocket> _clients = new List<WebSocket>();
        private ConcurrentDictionary<WebSocket, SemaphoreSlim> _socketLocks = new ConcurrentDictionary<WebSocket, SemaphoreSlim>();
        private MachineBridge _bridge;
        private bool _isRunning = false;

        public WebSocketServer(string url, MachineBridge bridge)
        {
            _bridge = bridge;
            _httpListener = new HttpListener();
            _httpListener.Prefixes.Add(url);
        }

        public void Start()
        {
            if (_isRunning) return;

            try
            {
                _httpListener.Start();
                _isRunning = true;
                Console.WriteLine($"[WS] GroupWare WebSocket Server Started");
                Task.Run(AcceptConnections);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[WS] Start Error: {ex.Message}");
            }
        }

        public void Stop()
        {
            _isRunning = false;
            try
            {
                _httpListener.Stop();
                _httpListener.Close();
            }
            catch { }
        }

        private async Task AcceptConnections()
        {
            while (_httpListener.IsListening && _isRunning)
            {
                try
                {
                    var context = await _httpListener.GetContextAsync();
                    if (context.Request.IsWebSocketRequest)
                    {
                        ProcessRequest(context);
                    }
                    else
                    {
                        context.Response.StatusCode = 400;
                        context.Response.Close();
                    }
                }
                catch (Exception ex)
                {
                    if (_isRunning)
                        Console.WriteLine($"[WS] Accept Error: {ex.Message}");
                }
            }
        }

        private async void ProcessRequest(HttpListenerContext context)
        {
            WebSocketContext wsContext = null;
            try
            {
                wsContext = await context.AcceptWebSocketAsync(subProtocol: null);
                WebSocket socket = wsContext.WebSocket;
                _socketLocks.TryAdd(socket, new SemaphoreSlim(1, 1));

                lock (_clients) { _clients.Add(socket); }
                Console.WriteLine("[WS] Client Connected");

                await ReceiveLoop(socket);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[WS] Process Error: {ex.Message}");
            }
            finally
            {
                if (wsContext != null)
                {
                    WebSocket socket = wsContext.WebSocket;
                    lock (_clients) { _clients.Remove(socket); }

                    if (_socketLocks.TryRemove(socket, out var semaphore))
                    {
                        semaphore.Dispose();
                    }
                    socket.Dispose();
                }
            }
        }

        private async Task ReceiveLoop(WebSocket socket)
        {
            var buffer = new byte[1024 * 4];
            while (socket.State == WebSocketState.Open && _isRunning)
            {
                try
                {
                    var result = await socket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
                    if (result.MessageType == WebSocketMessageType.Close)
                    {
                        await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None);
                    }
                    else if (result.MessageType == WebSocketMessageType.Text)
                    {
                        string msg = Encoding.UTF8.GetString(buffer, 0, result.Count);
                        await HandleMessage(msg, socket);
                    }
                }
                catch
                {
                    break;
                }
            }
        }

        private async Task HandleMessage(string msg, WebSocket socket)
        {
            try
            {
                dynamic json = JsonConvert.DeserializeObject(msg);
                string type = json.type;

                Console.WriteLine($"[WS] Message: {type}");

                switch (type)
                {
                    // ===== Todo API =====
                    case "GET_TODOS":
                        {
                            string result = _bridge.Todo_GetTodos();
                            var response = new { type = "TODOS_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "GET_TODO":
                        {
                            int id = json.id;
                            string result = _bridge.GetTodo(id);
                            var response = new { type = "TODO_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "CREATE_TODO":
                        {
                            string title = json.title ?? "";
                            string remark = json.remark ?? "";
                            string expire = json.expire;
                            int seqno = json.seqno ?? 0;
                            bool flag = json.flag ?? false;
                            string request = json.request;
                            string status = json.status ?? "0";

                            string result = _bridge.CreateTodo(title, remark, expire, seqno, flag, request, status);
                            var response = new { type = "TODO_CREATED", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "UPDATE_TODO":
                        {
                            int idx = json.idx;
                            string title = json.title ?? "";
                            string remark = json.remark ?? "";
                            string expire = json.expire;
                            int seqno = json.seqno ?? 0;
                            bool flag = json.flag ?? false;
                            string request = json.request;
                            string status = json.status ?? "0";

                            string result = _bridge.Todo_UpdateTodo(idx, title, remark, expire, seqno, flag, request, status);
                            var response = new { type = "TODO_UPDATED", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "DELETE_TODO":
                        {
                            int id = json.id;
                            string result = _bridge.Todo_DeleteTodo(id);
                            var response = new { type = "TODO_DELETED", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "GET_URGENT_TODOS":
                        {
                            string result = _bridge.GetUrgentTodos();
                            var response = new { type = "URGENT_TODOS_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    // ===== Dashboard API =====
                    case "GET_PURCHASE_WAIT_COUNT":
                        {
                            string result = _bridge.GetPurchaseWaitCount();
                            var response = new { type = "PURCHASE_WAIT_COUNT_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "GET_TODAY_COUNT_H":
                        {
                            string result = _bridge.TodayCountH();
                            var response = new { type = "TODAY_COUNT_H_DATA", count = int.Parse(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "GET_HOLY_USER":
                        {
                            string result = _bridge.GetHolyUser();
                            var response = new { type = "HOLY_USER_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "GET_HOLY_REQUEST_USER":
                        {
                            string result = _bridge.GetHolyRequestUser();
                            var response = new { type = "HOLY_REQUEST_USER_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "GET_PURCHASE_NR_LIST":
                        {
                            string result = _bridge.GetPurchaseNRList();
                            var response = new { type = "PURCHASE_NR_LIST_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "GET_PURCHASE_CR_LIST":
                        {
                            string result = _bridge.GetPurchaseCRList();
                            var response = new { type = "PURCHASE_CR_LIST_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "GET_HOLYDAY_REQUEST_COUNT":
                        {
                            string result = _bridge.GetHolydayRequestCount();
                            var response = new { type = "HOLYDAY_REQUEST_COUNT_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "GET_CURRENT_USER_COUNT":
                        {
                            string result = _bridge.GetCurrentUserCount();
                            var response = new { type = "CURRENT_USER_COUNT_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    // ===== Login API =====
                    case "CHECK_LOGIN_STATUS":
                        {
                            string result = _bridge.CheckLoginStatus();
                            var response = new { type = "LOGIN_STATUS_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "LOGIN":
                        {
                            string gcode = json.gcode ?? "";
                            string id = json.id ?? "";
                            string password = json.password ?? "";
                            bool rememberMe = json.rememberMe ?? false;
                            string result = _bridge.Login(gcode, id, password, rememberMe);
                            var response = new { type = "LOGIN_RESULT", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "LOGOUT":
                        {
                            string result = _bridge.Logout();
                            var response = new { type = "LOGOUT_RESULT", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "GET_USER_GROUPS":
                        {
                            string result = _bridge.GetUserGroups();
                            var response = new { type = "USER_GROUPS_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "GET_PREVIOUS_LOGIN_INFO":
                        {
                            string result = _bridge.GetPreviousLoginInfo();
                            var response = new { type = "PREVIOUS_LOGIN_INFO_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    // ===== User API =====
                    case "GET_CURRENT_USER_INFO":
                        {
                            string result = _bridge.GetCurrentUserInfo();
                            var response = new { type = "CURRENT_USER_INFO_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "GET_USER_INFO_BY_ID":
                        {
                            string userId = json.userId ?? "";
                            string result = _bridge.GetUserInfoById(userId);
                            var response = new { type = "USER_INFO_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "SAVE_USER_INFO":
                        {
                            string userData = JsonConvert.SerializeObject(json.userData);
                            string result = _bridge.SaveUserInfo(userData);
                            var response = new { type = "USER_INFO_SAVED", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "CHANGE_PASSWORD":
                        {
                            string oldPassword = json.oldPassword ?? "";
                            string newPassword = json.newPassword ?? "";
                            string result = _bridge.ChangePassword(oldPassword, newPassword);
                            var response = new { type = "PASSWORD_CHANGED", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    // ===== Common Code API =====
                    case "COMMON_GET_GROUPS":
                        {
                            string result = _bridge.Common_GetGroups();
                            var response = new { type = "COMMON_GROUPS_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "COMMON_GET_LIST":
                        {
                            string grp = json.grp ?? "99";
                            string result = _bridge.Common_GetList(grp);
                            var response = new { type = "COMMON_LIST_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "COMMON_SAVE":
                        {
                            int idx = json.idx ?? 0;
                            string grp = json.grp ?? "";
                            string code = json.code ?? "";
                            string svalue = json.svalue ?? "";
                            int ivalue = json.ivalue ?? 0;
                            float fvalue = json.fvalue ?? 0f;
                            string svalue2 = json.svalue2 ?? "";
                            string memo = json.memo ?? "";
                            string result = _bridge.Common_Save(idx, grp, code, svalue, ivalue, fvalue, svalue2, memo);
                            var response = new { type = "COMMON_SAVED", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "COMMON_DELETE":
                        {
                            int idx = json.idx ?? 0;
                            string result = _bridge.Common_Delete(idx);
                            var response = new { type = "COMMON_DELETED", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "FAVORITE_GET_LIST":
                        {
                            string result = _bridge.Favorite_GetList();
                            var response = new { type = "FAVORITE_LIST_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    // ===== Items API =====
                    case "ITEMS_GET_CATEGORIES":
                        {
                            string result = _bridge.Items_GetCategories();
                            var response = new { type = "ITEMS_CATEGORIES_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "ITEMS_GET_LIST":
                        {
                            string category = json.category ?? "";
                            string searchKey = json.searchKey ?? "";
                            string result = _bridge.Items_GetList(category, searchKey);
                            var response = new { type = "ITEMS_LIST_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "ITEMS_SAVE":
                        {
                            int idx = json.idx ?? 0;
                            string sid = json.sid ?? "";
                            string cate = json.cate ?? "";
                            string name = json.name ?? "";
                            string model = json.model ?? "";
                            string scale = json.scale ?? "";
                            string unit = json.unit ?? "";
                            decimal price = json.price ?? 0m;
                            string supply = json.supply ?? "";
                            string manu = json.manu ?? "";
                            string storage = json.storage ?? "";
                            bool disable = json.disable ?? false;
                            string memo = json.memo ?? "";
                            string result = _bridge.Items_Save(idx, sid, cate, name, model, scale, unit, price, supply, manu, storage, disable, memo);
                            var response = new { type = "ITEMS_SAVED", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "ITEMS_DELETE":
                        {
                            int idx = json.idx ?? 0;
                            string result = _bridge.Items_Delete(idx);
                            var response = new { type = "ITEMS_DELETED", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "ITEMS_GET_IMAGE":
                        {
                            int idx = json.idx ?? 0;
                            string result = _bridge.Items_GetImage(idx);
                            var response = new { type = "ITEMS_IMAGE_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "ITEMS_SAVE_IMAGE":
                        {
                            int idx = json.idx ?? 0;
                            string base64Image = json.base64Image ?? "";
                            string result = _bridge.Items_SaveImage(idx, base64Image);
                            var response = new { type = "ITEMS_IMAGE_SAVED", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "ITEMS_DELETE_IMAGE":
                        {
                            int idx = json.idx ?? 0;
                            string result = _bridge.Items_DeleteImage(idx);
                            var response = new { type = "ITEMS_IMAGE_DELETED", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "ITEMS_GET_DETAIL":
                        {
                            int idx = json.idx ?? 0;
                            string result = _bridge.Items_GetDetail(idx);
                            var response = new { type = "ITEMS_DETAIL_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "ITEMS_GET_SUPPLIER_STAFF":
                        {
                            int supplyIdx = json.supplyIdx ?? 0;
                            string result = _bridge.Items_GetSupplierStaff(supplyIdx);
                            var response = new { type = "ITEMS_SUPPLIER_STAFF_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "ITEMS_GET_INCOMING_HISTORY":
                        {
                            int itemIdx = json.itemIdx ?? 0;
                            string result = _bridge.Items_GetIncomingHistory(itemIdx);
                            var response = new { type = "ITEMS_INCOMING_HISTORY_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "ITEMS_GET_ORDER_HISTORY":
                        {
                            int itemIdx = json.itemIdx ?? 0;
                            string result = _bridge.Items_GetOrderHistory(itemIdx);
                            var response = new { type = "ITEMS_ORDER_HISTORY_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    // ===== UserList API =====
                    case "USERLIST_GET_CURRENT_LEVEL":
                        {
                            string result = _bridge.UserList_GetCurrentLevel();
                            var response = new { type = "USERLIST_CURRENT_LEVEL_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "USERLIST_GET_DEPTS":
                        {
                            string result = _bridge.UserList_GetDepts();
                            var response = new { type = "USERLIST_DEPTS_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "USERLIST_GET_LIST":
                        {
                            string process = json.process ?? "%";
                            string result = _bridge.UserList_GetList(process);
                            var response = new { type = "USERLIST_LIST_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "USERLIST_GET_USER":
                        {
                            string userId = json.userId ?? "";
                            string result = _bridge.UserList_GetUser(userId);
                            var response = new { type = "USERLIST_USER_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "USERLIST_SAVE_GROUP_USER":
                        {
                            string userId = json.userId ?? "";
                            string dept = json.dept ?? "";
                            int level = json.level ?? 1;
                            bool useUserState = json.useUserState ?? false;
                            bool useJobReport = json.useJobReport ?? false;
                            bool exceptHoly = json.exceptHoly ?? false;
                            string result = _bridge.UserList_SaveGroupUser(userId, dept, level, useUserState, useJobReport, exceptHoly);
                            var response = new { type = "USERLIST_SAVED", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "USERLIST_SAVE_USER_FULL":
                        {
                            string userData = JsonConvert.SerializeObject(json.userData);
                            string result = _bridge.UserList_SaveUserFull(userData);
                            var response = new { type = "USERLIST_USER_FULL_SAVED", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "USERLIST_DELETE_GROUP_USER":
                        {
                            string userId = json.userId ?? "";
                            string result = _bridge.UserList_DeleteGroupUser(userId);
                            var response = new { type = "USERLIST_DELETED", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;


                    // ===== JobReport API (JobReport 뷰/테이블) =====
                    case "JOBREPORT_GET_LIST":
                        {
                            string sd = json.sd ?? "";
                            string ed = json.ed ?? "";
                            string uid = json.uid ?? "";
                            string cate = json.cate ?? "";  // 사용안함 (호환성)
                            string searchKey = json.searchKey ?? "";
                            string requestId = json.requestId;
                            Console.WriteLine($"[WS] JOBREPORT_GET_LIST: sd={sd}, ed={ed}, uid={uid}, searchKey={searchKey}");
                            string result = _bridge.Jobreport_GetList(sd, ed, uid, cate, searchKey);
                            var response = new { type = "JOBREPORT_LIST_DATA", data = JsonConvert.DeserializeObject(result), requestId = requestId };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "JOBREPORT_GET_USERS":
                        {
                            string result = _bridge.Jobreport_GetUsers();
                            var response = new { type = "JOBREPORT_USERS_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "JOBREPORT_GET_DETAIL":
                        {
                            int idx = json.idx ?? 0;
                            string result = _bridge.Jobreport_GetDetail(idx);
                            var response = new { type = "JOBREPORT_DETAIL_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "JOBREPORT_ADD":
                        {
                            string pdate = json.pdate ?? "";
                            string projectName = json.projectName ?? "";
                            int pidx = json.pidx ?? -1;
                            string requestpart = json.requestpart ?? "";
                            string package = json.package ?? "";
                            string jobType = json.jobType ?? "";  // type -> jobType (WebSocket type 필드 충돌 방지)
                            string process = json.process ?? "";
                            string status = json.status ?? "진행 완료";
                            string description = json.description ?? "";
                            double hrs = json.hrs ?? 0.0;
                            double ot = json.ot ?? 0.0;
                            string jobgrp = json.jobgrp ?? "";
                            string tag = json.tag ?? "";
                            string otStart = json.otStart ?? "00:00";
                            string otEnd = json.otEnd ?? "00:00";
                            string result = _bridge.Jobreport_Add(pdate, projectName, pidx, requestpart, package, jobType, process, status, description, hrs, ot, jobgrp, tag, otStart, otEnd);
                            var response = new { type = "JOBREPORT_ADDED", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "JOBREPORT_EDIT":
                        {
                            int idx = json.idx ?? 0;
                            string pdate = json.pdate ?? "";
                            string projectName = json.projectName ?? "";
                            int pidx = json.pidx ?? -1;
                            string requestpart = json.requestpart ?? "";
                            string package = json.package ?? "";
                            string jobType = json.jobType ?? "";  // type -> jobType (WebSocket type 필드 충돌 방지)
                            string process = json.process ?? "";
                            string status = json.status ?? "";
                            string description = json.description ?? "";
                            double hrs = json.hrs ?? 0.0;
                            double ot = json.ot ?? 0.0;
                            string jobgrp = json.jobgrp ?? "";
                            string tag = json.tag ?? "";
                            string otStart = json.otStart ?? "00:00";
                            string otEnd = json.otEnd ?? "00:00";
                            string result = _bridge.Jobreport_Edit(idx, pdate, projectName, pidx, requestpart, package, jobType, process, status, description, hrs, ot, jobgrp, tag, otStart, otEnd);
                            var response = new { type = "JOBREPORT_EDITED", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "JOBREPORT_DELETE":
                        {
                            int idx = json.idx ?? 0;
                            string result = _bridge.Jobreport_Delete(idx);
                            var response = new { type = "JOBREPORT_DELETED", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "JOBREPORT_GET_PERMISSION":
                        {
                            string targetUserId = json.targetUserId ?? "";
                            string result = _bridge.Jobreport_GetPermission(targetUserId);
                            var response = new { type = "JOBREPORT_PERMISSION", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "JOBREPORT_GET_LAST_BY_PROJECT":
                        {
                            int pidx = json.pidx ?? -1;
                            string projectName = json.projectName ?? "";
                            string result = _bridge.Jobreport_GetLastByProject(pidx, projectName);
                            var response = new { type = "JOBREPORT_LAST_BY_PROJECT", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "JOBREPORT_GET_JOBTYPES":
                        {
                            string process = json.process ?? "";
                            string result = _bridge.Jobreport_GetJobTypes(process);
                            var response = new { type = "JOBREPORT_JOBTYPES", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "GET_APP_VERSION":
                        {
                            string result = _bridge.GetAppVersion();
                            var response = new { type = "APP_VERSION", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    // ===== Kuntae API =====
                    case "GET_KUNTAE_LIST":
                        {
                            string sd = json.sd ?? "";
                            string ed = json.ed ?? "";
                            string result = _bridge.Kuntae_GetList(sd, ed);
                            var response = new { type = "KUNTAE_LIST_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "DELETE_KUNTAE":
                        {
                            int id = json.id ?? 0;
                            string result = _bridge.Kuntae_Delete(id);
                            var response = new { type = "KUNTAE_DELETED", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    // ===== Holyday (근태) API =====
                    case "HOLYDAY_GET_LIST":
                        {
                            string sd = json.sd ?? "";
                            string ed = json.ed ?? "";
                            string uid = json.uid ?? "%";
                            string result = _bridge.Holyday_GetList(sd, ed, uid);
                            var response = new { type = "HOLYDAY_LIST_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "HOLYDAY_GET_DETAIL":
                        {
                            int idx = json.idx ?? 0;
                            string result = _bridge.Holyday_GetDetail(idx);
                            var response = new { type = "HOLYDAY_DETAIL_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "HOLYDAY_ADD":
                        {
                            string cate = json.cate ?? "";
                            string sdate = json.sdate ?? "";
                            string edate = json.edate ?? "";
                            double term = json.term ?? 0.0;
                            double crtime = json.crtime ?? 0.0;
                            double termDr = json.termDr ?? 0.0;
                            double drTime = json.drTime ?? 0.0;
                            string contents = json.contents ?? "";
                            string uid = json.uid ?? "";
                            string result = _bridge.Holyday_Add(cate, sdate, edate, term, crtime, termDr, drTime, contents, uid);
                            var response = new { type = "HOLYDAY_ADDED", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "HOLYDAY_EDIT":
                        {
                            int idx = json.idx ?? 0;
                            string cate = json.cate ?? "";
                            string sdate = json.sdate ?? "";
                            string edate = json.edate ?? "";
                            double term = json.term ?? 0.0;
                            double crtime = json.crtime ?? 0.0;
                            double termDr = json.termDr ?? 0.0;
                            double drTime = json.drTime ?? 0.0;
                            string contents = json.contents ?? "";
                            string result = _bridge.Holyday_Edit(idx, cate, sdate, edate, term, crtime, termDr, drTime, contents);
                            var response = new { type = "HOLYDAY_EDITED", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "HOLYDAY_DELETE":
                        {
                            int idx = json.idx ?? 0;
                            string result = _bridge.Holyday_Delete(idx);
                            var response = new { type = "HOLYDAY_DELETED", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "HOLYDAY_GET_USERLIST":
                        {
                            string sd = json.sd ?? "";
                            string ed = json.ed ?? "";
                            string result = _bridge.Holyday_GetUserList(sd, ed);
                            var response = new { type = "HOLYDAY_USERLIST_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "HOLYDAY_GET_PERMISSION":
                        {
                            string result = _bridge.Holyday_GetPermission();
                            var response = new { type = "HOLYDAY_PERMISSION_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "HOLYDAY_GET_BALANCE":
                        {
                            string year = json.year ?? "";
                            string uid = json.uid ?? "";
                            string result = _bridge.Holyday_GetBalance(year, uid);
                            var response = new { type = "HOLYDAY_BALANCE_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;


                    // ===== Note API (메모장) =====
                    case "NOTE_GET_LIST":
                        {
                            string startDate = json.startDate ?? "";
                            string endDate = json.endDate ?? "";
                            string uid = json.uid ?? "";
                            string result = _bridge.Note_GetList(startDate, endDate, uid);
                            var response = new { type = "NOTE_LIST_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "NOTE_GET_DETAIL":
                        {
                            int idx = json.idx ?? 0;
                            string result = _bridge.Note_GetDetail(idx);
                            var response = new { type = "NOTE_DETAIL_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "NOTE_ADD":
                        {
                            string pdate = json.pdate ?? "";
                            string title = json.title ?? "";
                            string uid = json.uid ?? "";
                            string description = json.description ?? "";
                            string description2 = json.description2 ?? "";
                            bool share = json.share ?? false;
                            string guid = json.guid ?? "";
                            string result = _bridge.Note_Add(pdate, title, uid, description, description2, share, guid);
                            var response = new { type = "NOTE_ADDED", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "NOTE_EDIT":
                        {
                            int idx = json.idx ?? 0;
                            string pdate = json.pdate ?? "";
                            string title = json.title ?? "";
                            string uid = json.uid ?? "";
                            string description = json.description ?? "";
                            string description2 = json.description2 ?? "";
                            bool share = json.share ?? false;
                            string guid = json.guid ?? "";
                            string result = _bridge.Note_Edit(idx, pdate, title, uid, description, description2, share, guid);
                            var response = new { type = "NOTE_EDITED", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "NOTE_DELETE":
                        {
                            int idx = json.idx ?? 0;
                            string result = _bridge.Note_Delete(idx);
                            var response = new { type = "NOTE_DELETED", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    // ===== Board API (게시판 - 패치내역 등) =====
                    case "BOARD_GET_LIST":
                        {
                            int bidx = json.bidx ?? 5;
                            string searchKey = json.searchKey ?? "";
                            string result = _bridge.Board_GetList(bidx, searchKey);
                            var response = new { type = "BOARD_LIST_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "BOARD_GET_DETAIL":
                        {
                            int idx = json.idx ?? 0;
                            string result = _bridge.Board_GetDetail(idx);
                            var response = new { type = "BOARD_DETAIL_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "BOARD_ADD":
                        {
                            int bidx = json.bidx ?? 5;
                            string header = json.header ?? "";
                            string cate = json.cate ?? "";
                            string title = json.title ?? "";
                            string contents = json.contents ?? "";
                            string result = _bridge.Board_Add(bidx, header, cate, title, contents);
                            var response = new { type = "BOARD_ADDED", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "BOARD_EDIT":
                        {
                            int idx = json.idx ?? 0;
                            string header = json.header ?? "";
                            string cate = json.cate ?? "";
                            string title = json.title ?? "";
                            string contents = json.contents ?? "";
                            string result = _bridge.Board_Edit(idx, header, cate, title, contents);
                            var response = new { type = "BOARD_EDITED", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "BOARD_DELETE":
                        {
                            int idx = json.idx ?? 0;
                            string result = _bridge.Board_Delete(idx);
                            var response = new { type = "BOARD_DELETED", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "BOARD_GET_REPLIES":
                        {
                            int rootIdx = json.rootIdx ?? 0;
                            string result = _bridge.Board_GetReplies(rootIdx);
                            var response = new { type = "BOARD_REPLIES_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "BOARD_ADD_REPLY":
                        {
                            int rootIdx = json.rootIdx ?? 0;
                            int pidx = json.pidx ?? 0;
                            string title = json.title ?? "";
                            string contents = json.contents ?? "";
                            bool isComment = json.isComment ?? false;
                            string result = _bridge.Board_AddReply(rootIdx, pidx, title, contents, isComment);
                            var response = new { type = "BOARD_REPLY_ADDED", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    // ===== Mail API (메일 발신 내역) =====
                    case "MAIL_GET_LIST":
                        {
                            string startDate = json.startDate ?? "";
                            string endDate = json.endDate ?? "";
                            string searchKey = json.searchKey ?? "";
                            string result = _bridge.Mail_GetList(startDate, endDate, searchKey);
                            var response = new { type = "MAIL_LIST_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "MAIL_ADD_DATA":
                        {
                            string cate = json.cate ?? "";
                            string subject = json.subject ?? "";
                            string fromlist = json.fromlist ?? "";
                            string tolist = json.tolist ?? "";
                            string cc = json.cc ?? "";
                            string bcc = json.bcc ?? "";
                            string body = json.body ?? "";
                            string result = _bridge.Mail_AddData(cate, subject, fromlist, tolist, cc, bcc, body);
                            var response = new { type = "MAIL_ADD_DATA_RESULT", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "MAIL_SEND_DIRECT":
                        {
                            string cate = json.cate ?? "";
                            string subject = json.subject ?? "";
                            string fromlist = json.fromlist ?? "";
                            string tolist = json.tolist ?? "";
                            string cc = json.cc ?? "";
                            string bcc = json.bcc ?? "";
                            string body = json.body ?? "";
                            string result = _bridge.Mail_SendDirect(cate, subject, fromlist, tolist, cc, bcc, body);
                            var response = new { type = "MAIL_SEND_DIRECT_RESULT", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "MAIL_SEND_OUTLOOK":
                        {
                            string subject = json.subject ?? "";
                            string tolist = json.tolist ?? "";
                            string cc = json.cc ?? "";
                            string bcc = json.bcc ?? "";
                            string body = json.body ?? "";
                            string result = _bridge.Mail_SendOutlook(subject, tolist, cc, bcc, body);
                            var response = new { type = "MAIL_SEND_OUTLOOK_RESULT", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    // ===== License API (라이선스 관리) =====
                    case "LICENSE_GET_LIST":
                        {
                            string result = _bridge.License_GetList();
                            var response = new { type = "LICENSE_LIST_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "LICENSE_ADD":
                        {
                            string name = json.name ?? "";
                            string version = json.version ?? "";
                            string meterialNo = json.meterialNo ?? "";
                            string supply = json.supply ?? "";
                            int qty = json.qty ?? 0;
                            string uids = json.uids ?? "";
                            string serialNo = json.serialNo ?? "";
                            string remark = json.remark ?? "";
                            string sdate = json.sdate ?? "";
                            string edate = json.edate ?? "";
                            string manu = json.manu ?? "";
                            bool expire = json.expire ?? false;
                            string result = _bridge.License_Add(name, version, meterialNo, supply, qty, uids, serialNo, remark, sdate, edate, manu, expire);
                            var response = new { type = "LICENSE_ADD_RESULT", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "LICENSE_UPDATE":
                        {
                            int idx = json.idx ?? 0;
                            string name = json.name ?? "";
                            string version = json.version ?? "";
                            string meterialNo = json.meterialNo ?? "";
                            string supply = json.supply ?? "";
                            int qty = json.qty ?? 0;
                            string uids = json.uids ?? "";
                            string serialNo = json.serialNo ?? "";
                            string remark = json.remark ?? "";
                            string sdate = json.sdate ?? "";
                            string edate = json.edate ?? "";
                            string manu = json.manu ?? "";
                            bool expire = json.expire ?? false;
                            string result = _bridge.License_Update(idx, name, version, meterialNo, supply, qty, uids, serialNo, remark, sdate, edate, manu, expire);
                            var response = new { type = "LICENSE_UPDATE_RESULT", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "LICENSE_DELETE":
                        {
                            int idx = json.idx ?? 0;
                            string result = _bridge.License_Delete(idx);
                            var response = new { type = "LICENSE_DELETE_RESULT", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "LICENSE_OPEN_FOLDER":
                        {
                            int idx = json.idx ?? 0;
                            string result = _bridge.License_OpenFolder(idx);
                            var response = new { type = "LICENSE_OPEN_FOLDER_RESULT", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "LICENSE_EXPORT_CSV":
                        {
                            string filePath = json.filePath ?? "";
                            string result = _bridge.License_ExportCSV(filePath);
                            var response = new { type = "LICENSE_EXPORT_CSV_RESULT", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    // ===== PartList API (파트리스트) =====
                    case "PARTLIST_GET_LIST":
                        {
                            int projectIdx = json.projectIdx ?? 0;
                            string result = _bridge.PartList_GetList(projectIdx);
                            var response = new { type = "PARTLIST_LIST_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "PARTLIST_SAVE":
                        {
                            int idx = json.idx ?? 0;
                            int projectIdx = json.projectIdx ?? 0;
                            string itemgroup = json.itemgroup ?? "";
                            string itemname = json.itemname ?? "";
                            string item = json.item ?? "";
                            string itemmodel = json.itemmodel ?? "";
                            string itemscale = json.itemscale ?? "";
                            string itemunit = json.itemunit ?? "";
                            double qty = json.qty ?? 0.0;
                            double price = json.price ?? 0.0;
                            string itemsupply = json.itemsupply ?? "";
                            int itemsupplyidx = json.itemsupplyidx ?? 0;
                            string itemmanu = json.itemmanu ?? "";
                            string itemsid = json.itemsid ?? "";
                            string option1 = json.option1 ?? "";
                            string remark = json.remark ?? "";
                            int no = json.no ?? 0;
                            double qtybuy = json.qtybuy ?? 0.0;
                            string result = _bridge.PartList_Save(idx, projectIdx, itemgroup, itemname, item, itemmodel, itemscale, itemunit, qty, price, itemsupply, itemsupplyidx, itemmanu, itemsid, option1, remark, no, qtybuy);
                            var response = new { type = "PARTLIST_SAVE_RESULT", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "PARTLIST_DELETE":
                        {
                            int idx = json.idx ?? 0;
                            string result = _bridge.PartList_Delete(idx);
                            var response = new { type = "PARTLIST_DELETE_RESULT", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    // ===== Customs API (업체정보) =====
                    case "CUSTOMS_GET_LIST":
                        {
                            string searchKey = json.searchKey ?? "";
                            string result = _bridge.Customs_GetList(searchKey);
                            var response = new { type = "CUSTOMS_LIST_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "CUSTOMS_GET_DETAIL":
                        {
                            int idx = json.idx ?? 0;
                            string result = _bridge.Customs_GetDetail(idx);
                            var response = new { type = "CUSTOMS_DETAIL_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    // ===== Holiday API (월별근무표) =====
                    case "HOLIDAY_GET_LIST":
                        {
                            string month = json.month ?? "";
                            string result = _bridge.Holiday_GetList(month);
                            var response = new { type = "HOLIDAY_LIST_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "HOLIDAY_SAVE":
                        {
                            string month = json.month ?? "";
                            string holidaysJson = JsonConvert.SerializeObject(json.holidays);
                            string result = _bridge.Holiday_Save(month, holidaysJson);
                            var response = new { type = "HOLIDAY_SAVED", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "HOLIDAY_INITIALIZE":
                        {
                            string month = json.month ?? "";
                            string result = _bridge.Holiday_Initialize(month);
                            var response = new { type = "HOLIDAY_INITIALIZED", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    // ===== HolidayRequest API (휴가/외출 신청) =====
                    case "HOLIDAY_REQUEST_GET_LIST":
                        {
                            string startDate = json.startDate ?? "";
                            string endDate = json.endDate ?? "";
                            string userId = json.userId ?? "";
                            int userLevel = json.userLevel ?? 0;
                            string result = _bridge.HolidayRequest_GetList(startDate, endDate, userId, userLevel);
                            var response = new { type = "HOLIDAY_REQUEST_LIST_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "HOLIDAY_REQUEST_SAVE":
                        {
                            int idx = json.idx ?? 0;
                            string uid = json.uid ?? "";
                            string cate = json.cate ?? "";
                            string sdate = json.sdate ?? "";
                            string edate = json.edate ?? "";
                            string remark = json.remark ?? "";
                            string responseMsg = json.response ?? "";
                            int conf = json.conf ?? 0;
                            string holyReason = json.holyReason ?? "";
                            string holyBackup = json.holyBackup ?? "";
                            string holyLocation = json.holyLocation ?? "";
                            decimal holyDays = json.holyDays ?? 0;
                            decimal holyTimes = json.holyTimes ?? 0;
                            string stime = json.stime ?? "";
                            string etime = json.etime ?? "";

                            string result = _bridge.HolidayRequest_Save(idx, uid, cate, sdate, edate, remark, responseMsg, conf, holyReason, holyBackup, holyLocation, holyDays, holyTimes, stime, etime);
                            var response = new { type = "HOLIDAY_REQUEST_SAVED", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    // ===== MailForm API (메일양식) =====
                    case "MAILFORM_GET_LIST":
                        {
                            string result = _bridge.MailForm_GetList();
                            var response = new { type = "MAILFORM_LIST_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "MAILFORM_GET_DETAIL":
                        {
                            int idx = json.idx ?? 0;
                            string result = _bridge.MailForm_GetDetail(idx);
                            var response = new { type = "MAILFORM_DETAIL_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "MAILFORM_ADD":
                        {
                            string cate = json.cate ?? "";
                            string title = json.title ?? "";
                            string tolist = json.tolist ?? "";
                            string bcc = json.bcc ?? "";
                            string cc = json.cc ?? "";
                            string subject = json.subject ?? "";
                            string tail = json.tail ?? "";
                            string body = json.body ?? "";
                            bool selfTo = json.selfTo ?? false;
                            bool selfCC = json.selfCC ?? false;
                            bool selfBCC = json.selfBCC ?? false;
                            string exceptmail = json.exceptmail ?? "";
                            string exceptmailcc = json.exceptmailcc ?? "";
                            string result = _bridge.MailForm_Add(cate, title, tolist, bcc, cc, subject, tail, body, selfTo, selfCC, selfBCC, exceptmail, exceptmailcc);
                            var response = new { type = "MAILFORM_ADDED", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "MAILFORM_EDIT":
                        {
                            int idx = json.idx ?? 0;
                            string cate = json.cate ?? "";
                            string title = json.title ?? "";
                            string tolist = json.tolist ?? "";
                            string bcc = json.bcc ?? "";
                            string cc = json.cc ?? "";
                            string subject = json.subject ?? "";
                            string tail = json.tail ?? "";
                            string body = json.body ?? "";
                            bool selfTo = json.selfTo ?? false;
                            bool selfCC = json.selfCC ?? false;
                            bool selfBCC = json.selfBCC ?? false;
                            string exceptmail = json.exceptmail ?? "";
                            string exceptmailcc = json.exceptmailcc ?? "";
                            string result = _bridge.MailForm_Edit(idx, cate, title, tolist, bcc, cc, subject, tail, body, selfTo, selfCC, selfBCC, exceptmail, exceptmailcc);
                            var response = new { type = "MAILFORM_EDITED", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "MAILFORM_DELETE":
                        {
                            int idx = json.idx ?? 0;
                            string result = _bridge.MailForm_Delete(idx);
                            var response = new { type = "MAILFORM_DELETED", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    // ===== UserGroup API (그룹정보/권한설정) =====
                    case "USERGROUP_GET_LIST":
                        {
                            string result = _bridge.UserGroup_GetList();
                            var response = new { type = "USERGROUP_LIST_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "USERGROUP_ADD":
                        {
                            string dept = json.dept ?? "";
                            string path_kj = json.path_kj ?? "";
                            int permission = json.permission ?? 1;
                            bool advpurchase = json.advpurchase ?? false;
                            bool advkisul = json.advkisul ?? false;
                            string managerinfo = json.managerinfo ?? "";
                            string devinfo = json.devinfo ?? "";
                            bool usemail = json.usemail ?? false;
                            string result = _bridge.UserGroup_Add(dept, path_kj, permission, advpurchase, advkisul, managerinfo, devinfo, usemail);
                            var response = new { type = "USERGROUP_ADDED", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "USERGROUP_EDIT":
                        {
                            string originalDept = json.originalDept ?? "";
                            string dept = json.dept ?? "";
                            string path_kj = json.path_kj ?? "";
                            int permission = json.permission ?? 1;
                            bool advpurchase = json.advpurchase ?? false;
                            bool advkisul = json.advkisul ?? false;
                            string managerinfo = json.managerinfo ?? "";
                            string devinfo = json.devinfo ?? "";
                            bool usemail = json.usemail ?? false;
                            string result = _bridge.UserGroup_Edit(originalDept, dept, path_kj, permission, advpurchase, advkisul, managerinfo, devinfo, usemail);
                            var response = new { type = "USERGROUP_EDITED", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "USERGROUP_DELETE":
                        {
                            string dept = json.dept ?? "";
                            string result = _bridge.UserGroup_Delete(dept);
                            var response = new { type = "USERGROUP_DELETED", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "USERGROUP_GET_PERMISSION_INFO":
                        {
                            string result = _bridge.UserGroup_GetPermissionInfo();
                            var response = new { type = "USERGROUP_PERMISSION_INFO", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    // ===== UserAuth API (사용자 권한) =====
                    case "USERAUTH_CAN_ACCESS":
                        {
                            string result = _bridge.UserAuth_CanAccess();
                            var response = new { type = "USERAUTH_CAN_ACCESS_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "USERAUTH_GET_LIST":
                        {
                            string result = _bridge.UserAuth_GetList();
                            var response = new { type = "USERAUTH_LIST_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "USERAUTH_SAVE":
                        {
                            int idx = json.idx ?? 0;
                            string user = json.user ?? "";
                            int account = json.account ?? 0;
                            int purchase = json.purchase ?? 0;
                            int purchaseEB = json.purchaseEB ?? 0;
                            int holyday = json.holyday ?? 0;
                            int project = json.project ?? 0;
                            int jobreport = json.jobreport ?? 0;
                            int scheapp = json.scheapp ?? 0;
                            int equipment = json.equipment ?? 0;
                            int otconfirm = json.otconfirm ?? 0;
                            int holyreq = json.holyreq ?? 0;
                            int kuntae = json.kuntae ?? 0;
                            string result = _bridge.UserAuth_Save(idx, user, account, purchase, purchaseEB, holyday, project, jobreport, scheapp, equipment, otconfirm, holyreq, kuntae);
                            var response = new { type = "USERAUTH_SAVED", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "USERAUTH_DELETE":
                        {
                            int idx = json.idx ?? 0;
                            string result = _bridge.UserAuth_Delete(idx);
                            var response = new { type = "USERAUTH_DELETED", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "USERAUTH_GET_FIELDS":
                        {
                            string result = _bridge.UserAuth_GetFields();
                            var response = new { type = "USERAUTH_FIELDS_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    // ===== 범용 권한 체크 API =====
                    case "CHECK_AUTH":
                        {
                            string authType = json.authType ?? "";
                            int requiredLevel = json.requiredLevel ?? 5;
                            string result = _bridge.CheckAuth(authType, requiredLevel);
                            var response = new { type = "CHECK_AUTH_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "GET_MY_AUTH":
                        {
                            string result = _bridge.GetMyAuth();
                            var response = new { type = "MY_AUTH_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    // ===== 프로젝트 검색 API (업무일지용) =====
                    case "PROJECT_SEARCH":
                        {
                            string keyword = json.keyword ?? "";
                            string result = _bridge.Project_Search(keyword);
                            var response = new { type = "PROJECT_SEARCH_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "PROJECT_GET_USER_PROJECTS":
                        {
                            string result = _bridge.Project_GetUserProjects();
                            var response = new { type = "PROJECT_USER_PROJECTS_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "PROJECT_GET_CATEGORIES":
                        {
                            string result = _bridge.Project_GetCategories();
                            var response = new { type = "PROJECT_CATEGORIES_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "PROJECT_GET_PROCESSES":
                        {
                            string result = _bridge.Project_GetProcesses();
                            var response = new { type = "PROJECT_PROCESSES_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "PROJECT_GET_LIST":
                        {
                            string statusFilter = json.statusFilter ?? "";
                            string category = json.category ?? "";
                            string process = json.process ?? "";
                            string userFilter = json.userFilter ?? "";
                            string yearStart = json.yearStart ?? "";
                            string yearEnd = json.yearEnd ?? "";
                            string dateType = json.dateType ?? "0";
                            string result = _bridge.Project_GetList(statusFilter, category, process, userFilter, yearStart, yearEnd, dateType);
                            var response = new { type = "PROJECT_LIST_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "PROJECT_GET_HISTORY":
                        {
                            int projectIdx = json.projectIdx ?? 0;
                            string result = _bridge.Project_GetHistory(projectIdx);
                            var response = new { type = "PROJECT_HISTORY_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "PROJECT_SAVE_HISTORY":
                        {
                            int idx = json.idx ?? 0;
                            int pidx = json.pidx ?? 0;
                            string pdate = json.pdate ?? "";
                            int progress = json.progress ?? 0;
                            string remark = json.remark ?? "";
                            string result = _bridge.Project_SaveHistory(idx, pidx, pdate, progress, remark);
                            var response = new { type = "PROJECT_SAVE_HISTORY_RESULT", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "PROJECT_GET_DAILY_MEMO":
                        {
                            int projectIdx = json.projectIdx ?? 0;
                            string result = _bridge.Project_GetDailyMemo(projectIdx);
                            var response = new { type = "PROJECT_DAILY_MEMO_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    // ===== 근태 오류검사 API =====
                    case "KUNTAE_ERROR_CHECK":
                        {
                            string sd = json.sd ?? "";
                            string ed = json.ed ?? "";
                            string result = _bridge.Kuntae_ErrorCheck(sd, ed);
                            var response = new { type = "KUNTAE_ERROR_CHECK_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "KUNTAE_FIX_ERROR":
                        {
                            string pdate = json.pdate ?? "";
                            string result = _bridge.Kuntae_FixError(pdate);
                            var response = new { type = "KUNTAE_FIX_ERROR_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    case "KUNTAE_FIX_ERRORS":
                        {
                            string dates = JsonConvert.SerializeObject(json.dates);
                            string result = _bridge.Kuntae_FixErrors(dates);
                            var response = new { type = "KUNTAE_FIX_ERRORS_DATA", data = JsonConvert.DeserializeObject(result) };
                            await Send(socket, JsonConvert.SerializeObject(response));
                        }
                        break;

                    default:
                        Console.WriteLine($"[WS] Unknown message type: {type}");
                        break;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[WS] Handle Error: {ex.Message}");
            }
        }

        private async Task Send(WebSocket socket, string message)
        {
            if (_socketLocks.TryGetValue(socket, out var semaphore))
            {
                await semaphore.WaitAsync();
                try
                {
                    if (socket.State == WebSocketState.Open)
                    {
                        byte[] buffer = Encoding.UTF8.GetBytes(message);
                        await socket.SendAsync(new ArraySegment<byte>(buffer), WebSocketMessageType.Text, true, CancellationToken.None);
                    }
                }
                finally
                {
                    semaphore.Release();
                }
            }
        }

        public async void Broadcast(string message)
        {
            byte[] buffer = Encoding.UTF8.GetBytes(message);
            WebSocket[] clientsCopy;

            lock (_clients)
            {
                clientsCopy = _clients.ToArray();
            }

            foreach (var client in clientsCopy)
            {
                if (client.State == WebSocketState.Open && _socketLocks.TryGetValue(client, out var semaphore))
                {
                    _ = Task.Run(async () =>
                    {
                        if (await semaphore.WaitAsync(0))
                        {
                            try
                            {
                                if (client.State == WebSocketState.Open)
                                {
                                    await client.SendAsync(new ArraySegment<byte>(buffer), WebSocketMessageType.Text, true, CancellationToken.None);
                                }
                            }
                            catch { }
                            finally
                            {
                                semaphore.Release();
                            }
                        }
                    });
                }
            }
        }
    }
}
