import type {
  ApiResponse,
  LoginStatusResponse,
  CheckAuthResponse,
  TodoModel,
  PurchaseItem,
  PurchaseCount,
  JobReportItem,
  JobReportUser,
  JobReportPermission,
  JobReportTypeItem,
  JobTypeItem,
  MailFormItem,
  UserGroupItem,
  PermissionInfo,
  AuthItem,
  AuthFieldInfo,
  AuthType,
  MyAuthInfo,
  ProjectSearchItem,
  NoteItem,
  KuntaeModel,
  HolydayBalance,
  HolyUser,
  HolyRequestUser,
  LoginResult,
  UserGroup,
  PreviousLoginInfo,
  UserInfoDetail,
  CommonCodeGroup,
  CommonCode,
  ItemInfo,
  ItemDetail,
  SupplierStaff,
  PurchaseHistoryItem,
  UserLevelInfo,
  GroupUser,
  UserFullData,
  AppVersionInfo,
  HolidayItem,
  MachineBridgeInterface,
  BoardItem,
  MailItem,
  CustomItem,
  LicenseItem,
  PartListItem,
  HolidayRequest,
  SettingsModel,
} from '@/types';

// WebView2 환경 감지
const isWebView = typeof window !== 'undefined' &&
  window.chrome?.webview?.hostObjects !== undefined;

const machine: MachineBridgeInterface | null = isWebView
  ? window.chrome!.webview!.hostObjects.machine
  : null;

type MessageCallback = (data: unknown) => void;

class CommunicationLayer {
  private listeners: MessageCallback[] = [];
  private ws: WebSocket | null = null;
  private isConnected = false;
  private wsUrl = 'ws://localhost:8082'; // GroupWare WebSocket 포트

  constructor() {
    if (isWebView) {
      console.log("[COMM] Running in WebView2 Mode (HostObject)");
      this.isConnected = true;
      window.chrome!.webview!.addEventListener('message', (event: MessageEvent) => {
        this.notifyListeners(event.data);
      });
      // WebView2 환경에서도 연결 상태 알림
      setTimeout(() => {
        this.notifyListeners({ type: 'CONNECTION_STATE', connected: true });
      }, 0);
    } else {
      console.log("[COMM] Running in Browser Mode (WebSocket)");
      this.connectWebSocket();
    }
  }

  public isWebViewMode(): boolean {
    return isWebView;
  }

  private connectWebSocket() {
    this.ws = new WebSocket(this.wsUrl);

    this.ws.onopen = () => {
      console.log("[COMM] WebSocket Connected");
      this.isConnected = true;
      this.notifyListeners({ type: 'CONNECTION_STATE', connected: true });
    };

    this.ws.onmessage = (event) => {
      try {
        const data = JSON.parse(event.data);
        this.notifyListeners(data);
      } catch (e) {
        console.error("[COMM] JSON Parse Error", e);
      }
    };

    this.ws.onclose = () => {
      console.log("[COMM] WebSocket Closed. Reconnecting...");
      this.isConnected = false;
      this.notifyListeners({ type: 'CONNECTION_STATE', connected: false });
      setTimeout(() => this.connectWebSocket(), 2000);
    };

    this.ws.onerror = (err) => {
      console.error("[COMM] WebSocket Error", err);
    };
  }

  private notifyListeners(data: unknown) {
    this.listeners.forEach(cb => cb(data));
  }

  public subscribe(callback: MessageCallback) {
    this.listeners.push(callback);
    return () => {
      this.listeners = this.listeners.filter(cb => cb !== callback);
    };
  }

  public getConnectionState(): boolean {
    return this.isConnected;
  }

  // WebSocket 요청-응답 헬퍼
  private wsRequest<T>(requestType: string, responseType: string, params?: Record<string, unknown>): Promise<T> {
    return new Promise((resolve, reject) => {
      if (!this.isConnected) {
        setTimeout(() => {
          if (!this.isConnected) reject(new Error("WebSocket connection timeout"));
        }, 2000);
      }

      const requestId = Date.now().toString() + Math.random().toString(36).substr(2, 9);

      const timeoutId = setTimeout(() => {
        this.listeners = this.listeners.filter(cb => cb !== handler);
        reject(new Error(`${requestType} timeout`));
      }, 10000);

      const handler = (data: unknown) => {
        const msg = data as { type: string; data?: T; Success?: boolean; Message?: string; requestId?: string };
        if (msg.type === responseType) {
          // requestId가 있는 경우 일치 여부 확인 (백엔드가 지원하는 경우)
          if (msg.requestId && msg.requestId !== requestId) {
            return;
          }

          clearTimeout(timeoutId);
          this.listeners = this.listeners.filter(cb => cb !== handler);
          resolve(msg.data as T);
        }
      };
      this.listeners.push(handler);
      this.ws?.send(JSON.stringify({ ...params, type: requestType, requestId }));
    });
  }

  // ===== Todo API =====

  public async getTodos(): Promise<ApiResponse<TodoModel[]>> {
    if (isWebView && machine) {
      const result = await machine.Todo_GetTodos();
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse<TodoModel[]>>('GET_TODOS', 'TODOS_DATA');
    }
  }

  public async getTodo(id: number): Promise<ApiResponse<TodoModel>> {
    if (isWebView && machine) {
      const result = await machine.Todo_GetTodo(id);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse<TodoModel>>('GET_TODO', 'TODO_DATA', { id });
    }
  }

  public async createTodo(
    title: string,
    remark: string,
    expire: string | null,
    seqno: number,
    flag: boolean,
    request: string | null,
    status: string
  ): Promise<ApiResponse<{ idx: number }>> {
    if (isWebView && machine) {
      const result = await machine.CreateTodo(title, remark, expire, seqno, flag, request, status);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse<{ idx: number }>>('CREATE_TODO', 'TODO_CREATED', {
        title, remark, expire, seqno, flag, request, status
      });
    }
  }

  public async updateTodo(
    idx: number,
    title: string,
    remark: string,
    expire: string | null,
    seqno: number,
    flag: boolean,
    request: string | null,
    status: string
  ): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.Todo_UpdateTodo(idx, title, remark, expire, seqno, flag, request, status);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('UPDATE_TODO', 'TODO_UPDATED', {
        idx, title, remark, expire, seqno, flag, request, status
      });
    }
  }

  public async deleteTodo(id: number): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.Todo_DeleteTodo(id);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('DELETE_TODO', 'TODO_DELETED', { id });
    }
  }

  public async getUrgentTodos(): Promise<ApiResponse<TodoModel[]>> {
    if (isWebView && machine) {
      const result = await machine.GetUrgentTodos();
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse<TodoModel[]>>('GET_URGENT_TODOS', 'URGENT_TODOS_DATA');
    }
  }

  // ===== Dashboard API =====

  public async getPurchaseWaitCount(): Promise<PurchaseCount> {
    if (isWebView && machine) {
      const result = await machine.GetPurchaseWaitCount();
      return JSON.parse(result);
    } else {
      return this.wsRequest<PurchaseCount>('GET_PURCHASE_WAIT_COUNT', 'PURCHASE_WAIT_COUNT_DATA');
    }
  }

  public async getTodayCountH(): Promise<number> {
    if (isWebView && machine) {
      const result = await machine.TodayCountH();
      return parseInt(result, 10);
    } else {
      const response = await this.wsRequest<{ count: number }>('GET_TODAY_COUNT_H', 'TODAY_COUNT_H_DATA');
      return response.count;
    }
  }

  public async getHolyUser(): Promise<HolyUser[]> {
    if (isWebView && machine) {
      const result = await machine.GetHolyUser();
      return JSON.parse(result);
    } else {
      return this.wsRequest<HolyUser[]>('GET_HOLY_USER', 'HOLY_USER_DATA');
    }
  }

  public async getHolyRequestUser(): Promise<HolyRequestUser[]> {
    if (isWebView && machine) {
      const result = await machine.GetHolyRequestUser();
      return JSON.parse(result);
    } else {
      return this.wsRequest<HolyRequestUser[]>('GET_HOLY_REQUEST_USER', 'HOLY_REQUEST_USER_DATA');
    }
  }

  public async getPurchaseNRList(): Promise<PurchaseItem[]> {
    if (isWebView && machine) {
      const result = await machine.GetPurchaseNRList();
      return JSON.parse(result);
    } else {
      return this.wsRequest<PurchaseItem[]>('GET_PURCHASE_NR_LIST', 'PURCHASE_NR_LIST_DATA');
    }
  }

  public async getPurchaseCRList(): Promise<PurchaseItem[]> {
    if (isWebView && machine) {
      const result = await machine.GetPurchaseCRList();
      return JSON.parse(result);
    } else {
      return this.wsRequest<PurchaseItem[]>('GET_PURCHASE_CR_LIST', 'PURCHASE_CR_LIST_DATA');
    }
  }

  public async getHolydayRequestCount(): Promise<{ HOLY: number; Message?: string }> {
    if (isWebView && machine) {
      const result = await machine.GetHolydayRequestCount();
      return JSON.parse(result);
    } else {
      return this.wsRequest<{ HOLY: number; Message?: string }>('GET_HOLYDAY_REQUEST_COUNT', 'HOLYDAY_REQUEST_COUNT_DATA');
    }
  }

  public async getCurrentUserCount(): Promise<{ Count: number; Message?: string }> {
    if (isWebView && machine) {
      const result = await machine.GetCurrentUserCount();
      return JSON.parse(result);
    } else {
      return this.wsRequest<{ Count: number; Message?: string }>('GET_CURRENT_USER_COUNT', 'CURRENT_USER_COUNT_DATA');
    }
  }

  // ===== Kuntae API =====

  public async getKuntaeList(sd: string, ed: string): Promise<ApiResponse<KuntaeModel[]>> {
    if (isWebView && machine) {
      const result = await machine.Kuntae_GetList(sd, ed);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse<KuntaeModel[]>>('GET_KUNTAE_LIST', 'KUNTAE_LIST_DATA', { sd, ed });
    }
  }

  public async deleteKuntae(id: number): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.Kuntae_Delete(id);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('DELETE_KUNTAE', 'KUNTAE_DELETED', { id });
    }
  }

  public async kuntaeErrorCheck(sd: string, ed: string): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.Kuntae_ErrorCheck(sd, ed);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('KUNTAE_ERROR_CHECK', 'KUNTAE_ERROR_CHECK_DATA', { sd, ed });
    }
  }

  public async kuntaeFixError(pdate: string): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.Kuntae_FixError(pdate);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('KUNTAE_FIX_ERROR', 'KUNTAE_FIX_ERROR_DATA', { pdate });
    }
  }

  public async kuntaeFixErrors(dates: string[]): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.Kuntae_FixErrors(JSON.stringify(dates));
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('KUNTAE_FIX_ERRORS', 'KUNTAE_FIX_ERRORS_DATA', { dates });
    }
  }

  // ===== Holyday (근태) API =====

  public async getHolydayList(sd: string, ed: string, uid: string = '%'): Promise<ApiResponse<KuntaeModel[]>> {
    return this.wsRequest<ApiResponse<KuntaeModel[]>>('HOLYDAY_GET_LIST', 'HOLYDAY_LIST_DATA', { sd, ed, uid });
  }

  public async getHolydayDetail(idx: number): Promise<ApiResponse<KuntaeModel>> {
    return this.wsRequest<ApiResponse<KuntaeModel>>('HOLYDAY_GET_DETAIL', 'HOLYDAY_DETAIL_DATA', { idx });
  }

  public async addHolyday(
    cate: string, sdate: string, edate: string, term: number, crtime: number,
    termDr: number, drTime: number, contents: string, uid: string
  ): Promise<ApiResponse> {
    return this.wsRequest<ApiResponse>('HOLYDAY_ADD', 'HOLYDAY_ADDED', {
      cate, sdate, edate, term, crtime, termDr, drTime, contents, uid
    });
  }

  public async editHolyday(
    idx: number, cate: string, sdate: string, edate: string, term: number, crtime: number,
    termDr: number, drTime: number, contents: string
  ): Promise<ApiResponse> {
    return this.wsRequest<ApiResponse>('HOLYDAY_EDIT', 'HOLYDAY_EDITED', {
      idx, cate, sdate, edate, term, crtime, termDr, drTime, contents
    });
  }

  public async deleteHolyday(idx: number): Promise<ApiResponse> {
    return this.wsRequest<ApiResponse>('HOLYDAY_DELETE', 'HOLYDAY_DELETED', { idx });
  }

  public async getHolydayUserList(sd: string, ed: string): Promise<ApiResponse> {
    return this.wsRequest<ApiResponse>('HOLYDAY_GET_USERLIST', 'HOLYDAY_USERLIST_DATA', { sd, ed });
  }

  public async getHolydayPermission(): Promise<ApiResponse> {
    return this.wsRequest<ApiResponse>('HOLYDAY_GET_PERMISSION', 'HOLYDAY_PERMISSION_DATA');
  }

  public async getHolydayBalance(year: string, uid: string): Promise<ApiResponse<HolydayBalance[]>> {
    return this.wsRequest<ApiResponse<HolydayBalance[]>>('HOLYDAY_GET_BALANCE', 'HOLYDAY_BALANCE_DATA', { year, uid });
  }

  // ===== Favorite API =====

  public async getFavoriteList(): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.Favorite_GetList();
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('FAVORITE_GET_LIST', 'FAVORITE_LIST_DATA');
    }
  }

  // ===== Project List API =====

  public async getProjectCategories(): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.Project_GetCategories();
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('PROJECT_GET_CATEGORIES', 'PROJECT_CATEGORIES_DATA');
    }
  }

  public async getProjectProcesses(): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.Project_GetProcesses();
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('PROJECT_GET_PROCESSES', 'PROJECT_PROCESSES_DATA');
    }
  }

  public async getProjectList(
    statusFilter: string,
    category: string,
    process: string,
    userFilter: string,
    yearStart: string,
    yearEnd: string,
    dateType: string
  ): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.Project_GetList(statusFilter, category, process, userFilter, yearStart, yearEnd, dateType);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('PROJECT_GET_LIST', 'PROJECT_LIST_DATA', {
        statusFilter, category, process, userFilter, yearStart, yearEnd, dateType
      });
    }
  }

  public async getProjectHistory(projectIdx: number): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.Project_GetHistory(projectIdx);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('PROJECT_GET_HISTORY', 'PROJECT_HISTORY_DATA', { projectIdx });
    }
  }

  public async getProjectDailyMemo(projectIdx: number): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.Project_GetDailyMemo(projectIdx);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('PROJECT_GET_DAILY_MEMO', 'PROJECT_DAILY_MEMO_DATA', { projectIdx });
    }
  }

  public async saveProjectHistory(historyData: { idx?: number; pidx: number; pdate: string; progress: number; remark: string }): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.Project_SaveHistory(
        historyData.idx || 0,
        historyData.pidx,
        historyData.pdate,
        historyData.progress,
        historyData.remark
      );
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('PROJECT_SAVE_HISTORY', 'PROJECT_SAVE_HISTORY_RESULT', historyData);
    }
  }


  // ===== Login API =====

  public async checkLoginStatus(): Promise<LoginStatusResponse> {
    if (isWebView && machine) {
      const result = await machine.CheckLoginStatus();
      return JSON.parse(result);
    } else {
      return this.wsRequest<LoginStatusResponse>('CHECK_LOGIN_STATUS', 'LOGIN_STATUS_DATA');
    }
  }

  public async login(gcode: string, id: string, password: string, rememberMe: boolean): Promise<LoginResult> {
    if (isWebView && machine) {
      const result = await machine.Login(gcode, id, password, rememberMe);
      return JSON.parse(result);
    } else {
      return this.wsRequest<LoginResult>('LOGIN', 'LOGIN_RESULT', { gcode, id, password, rememberMe });
    }
  }

  public async logout(): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.Logout();
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('LOGOUT', 'LOGOUT_RESULT');
    }
  }

  public async getUserGroups(): Promise<UserGroup[]> {
    if (isWebView && machine) {
      const result = await machine.GetUserGroups();
      return JSON.parse(result);
    } else {
      return this.wsRequest<UserGroup[]>('GET_USER_GROUPS', 'USER_GROUPS_DATA');
    }
  }

  public async getPreviousLoginInfo(): Promise<PreviousLoginInfo> {
    if (isWebView && machine) {
      const result = await machine.GetPreviousLoginInfo();
      return JSON.parse(result);
    } else {
      return this.wsRequest<PreviousLoginInfo>('GET_PREVIOUS_LOGIN_INFO', 'PREVIOUS_LOGIN_INFO_DATA');
    }
  }

  // ===== User API =====

  public async getCurrentUserInfo(): Promise<ApiResponse<UserInfoDetail>> {
    if (isWebView && machine) {
      const result = await machine.GetCurrentUserInfo();
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse<UserInfoDetail>>('GET_CURRENT_USER_INFO', 'CURRENT_USER_INFO_DATA');
    }
  }

  public async getUserInfoById(userId: string): Promise<ApiResponse<UserInfoDetail>> {
    if (isWebView && machine) {
      const result = await machine.GetUserInfoById(userId);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse<UserInfoDetail>>('GET_USER_INFO_BY_ID', 'USER_INFO_DATA', { userId });
    }
  }

  public async saveUserInfo(userData: UserInfoDetail): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.SaveUserInfo(JSON.stringify(userData));
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('SAVE_USER_INFO', 'USER_INFO_SAVED', { userData });
    }
  }

  public async changePassword(oldPassword: string, newPassword: string): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.ChangePassword(oldPassword, newPassword);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('CHANGE_PASSWORD', 'PASSWORD_CHANGED', { oldPassword, newPassword });
    }
  }

  // ===== Common Code API =====

  public async getCommonGroups(): Promise<CommonCodeGroup[]> {
    if (isWebView && machine) {
      const result = await machine.Common_GetGroups();
      return JSON.parse(result);
    } else {
      return this.wsRequest<CommonCodeGroup[]>('COMMON_GET_GROUPS', 'COMMON_GROUPS_DATA');
    }
  }

  public async getCommonList(grp: string): Promise<CommonCode[]> {
    if (isWebView && machine) {
      const result = await machine.Common_GetList(grp);
      return JSON.parse(result);
    } else {
      return this.wsRequest<CommonCode[]>('COMMON_GET_LIST', 'COMMON_LIST_DATA', { grp });
    }
  }

  public async saveCommon(data: CommonCode): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.Common_Save(
        data.idx, data.grp, data.code, data.svalue,
        data.ivalue, data.fvalue, data.svalue2 || '', data.memo
      );
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('COMMON_SAVE', 'COMMON_SAVED', data as unknown as Record<string, unknown>);
    }
  }

  public async deleteCommon(idx: number): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.Common_Delete(idx);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('COMMON_DELETE', 'COMMON_DELETED', { idx });
    }
  }

  // ===== Items API =====

  public async getItemCategories(): Promise<ApiResponse<string[]>> {
    if (isWebView && machine) {
      const result = await machine.Items_GetCategories();
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse<string[]>>('ITEMS_GET_CATEGORIES', 'ITEMS_CATEGORIES_DATA');
    }
  }

  public async getItemList(category: string, searchKey: string): Promise<ItemInfo[]> {
    if (isWebView && machine) {
      const result = await machine.Items_GetList(category, searchKey);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ItemInfo[]>('ITEMS_GET_LIST', 'ITEMS_LIST_DATA', { category, searchKey });
    }
  }

  public async saveItem(data: ItemInfo): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.Items_Save(
        data.idx, data.sid, data.cate, data.name, data.model,
        data.scale, data.unit, data.price, data.supply,
        data.manu, data.storage, data.disable, data.memo
      );
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('ITEMS_SAVE', 'ITEMS_SAVED', data as unknown as Record<string, unknown>);
    }
  }

  public async deleteItem(idx: number): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.Items_Delete(idx);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('ITEMS_DELETE', 'ITEMS_DELETED', { idx });
    }
  }

  public async getItemImage(idx: number): Promise<ApiResponse<string>> {
    if (isWebView && machine) {
      const result = await machine.Items_GetImage(idx);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse<string>>('ITEMS_GET_IMAGE', 'ITEMS_IMAGE_DATA', { idx });
    }
  }

  public async saveItemImage(idx: number, base64Image: string): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.Items_SaveImage(idx, base64Image);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('ITEMS_SAVE_IMAGE', 'ITEMS_IMAGE_SAVED', { idx, base64Image });
    }
  }

  public async deleteItemImage(idx: number): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.Items_DeleteImage(idx);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('ITEMS_DELETE_IMAGE', 'ITEMS_IMAGE_DELETED', { idx });
    }
  }

  public async getItemDetail(idx: number): Promise<ApiResponse<ItemDetail>> {
    if (isWebView && machine) {
      const result = await machine.Items_GetDetail(idx);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse<ItemDetail>>('ITEMS_GET_DETAIL', 'ITEMS_DETAIL_DATA', { idx });
    }
  }

  public async getSupplierStaff(supplyIdx: number): Promise<ApiResponse<SupplierStaff[]>> {
    if (isWebView && machine) {
      const result = await machine.Items_GetSupplierStaff(supplyIdx);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse<SupplierStaff[]>>('ITEMS_GET_SUPPLIER_STAFF', 'ITEMS_SUPPLIER_STAFF_DATA', { supplyIdx });
    }
  }

  public async getIncomingHistory(itemIdx: number): Promise<ApiResponse<PurchaseHistoryItem[]>> {
    if (isWebView && machine) {
      const result = await machine.Items_GetIncomingHistory(itemIdx);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse<PurchaseHistoryItem[]>>('ITEMS_GET_INCOMING_HISTORY', 'ITEMS_INCOMING_HISTORY_DATA', { itemIdx });
    }
  }

  public async getOrderHistory(itemIdx: number): Promise<ApiResponse<PurchaseHistoryItem[]>> {
    if (isWebView && machine) {
      const result = await machine.Items_GetOrderHistory(itemIdx);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse<PurchaseHistoryItem[]>>('ITEMS_GET_ORDER_HISTORY', 'ITEMS_ORDER_HISTORY_DATA', { itemIdx });
    }
  }

  // ===== UserList API =====

  public async getCurrentUserLevel(): Promise<ApiResponse<UserLevelInfo>> {
    if (isWebView && machine) {
      const result = await machine.UserList_GetCurrentLevel();
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse<UserLevelInfo>>('USERLIST_GET_CURRENT_LEVEL', 'USERLIST_CURRENT_LEVEL_DATA');
    }
  }

  public async getUserList(process: string): Promise<GroupUser[]> {
    if (isWebView && machine) {
      const result = await machine.UserList_GetList(process);
      return JSON.parse(result);
    } else {
      return this.wsRequest<GroupUser[]>('USERLIST_GET_LIST', 'USERLIST_LIST_DATA', { process });
    }
  }

  public async getUserListUser(userId: string): Promise<ApiResponse<GroupUser>> {
    if (isWebView && machine) {
      const result = await machine.UserList_GetUser(userId);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse<GroupUser>>('USERLIST_GET_USER', 'USERLIST_USER_DATA', { userId });
    }
  }

  public async saveGroupUser(
    userId: string, dept: string, level: number,
    useUserState: boolean, useJobReport: boolean, exceptHoly: boolean
  ): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.UserList_SaveGroupUser(userId, dept, level, useUserState, useJobReport, exceptHoly);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('USERLIST_SAVE_GROUP_USER', 'USERLIST_SAVED', {
        userId, dept, level, useUserState, useJobReport, exceptHoly
      });
    }
  }

  public async saveUserFull(userData: UserFullData): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.UserList_SaveUserFull(JSON.stringify(userData));
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('USERLIST_SAVE_USER_FULL', 'USERLIST_USER_FULL_SAVED', { userData });
    }
  }

  public async deleteGroupUser(userId: string): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.UserList_DeleteGroupUser(userId);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('USERLIST_DELETE_GROUP_USER', 'USERLIST_DELETED', { userId });
    }
  }

  // ===== JobReport API (JobReport 뷰/테이블) =====

  public async getJobReportList(sd: string, ed: string, uid: string = '', searchKey: string = ''): Promise<ApiResponse<JobReportItem[]>> {
    if (isWebView && machine) {
      const result = await machine.Jobreport_GetList(sd, ed, uid, '', searchKey);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse<JobReportItem[]>>('JOBREPORT_GET_LIST', 'JOBREPORT_LIST_DATA', { sd, ed, uid, searchKey });
    }
  }

  public async getJobReportUsers(): Promise<JobReportUser[]> {
    if (isWebView && machine) {
      const result = await machine.Jobreport_GetUsers();
      return JSON.parse(result);
    } else {
      return this.wsRequest<JobReportUser[]>('JOBREPORT_GET_USERS', 'JOBREPORT_USERS_DATA');
    }
  }

  // ===== Settings API =====

  public async getSettings(): Promise<ApiResponse<SettingsModel>> {
    if (isWebView && machine) {
      const result = await machine.GetSettings();
      // MachineBridge returns JSON string of the object directly
      // WebSocket wrap it in { type, data }
      // This helper handles webview vs websocket differences usually... 
      // Wait, MachineBridge.Settings.cs returns JsonConvert.SerializeObject(Pub.setting).
      // So result is string "{"Disable8HourOver": ...}"
      return { Success: true, Data: JSON.parse(result) };
    } else {
      return this.wsRequest<ApiResponse<SettingsModel>>('GET_SETTINGS', 'SETTINGS_DATA');
    }
  }

  public async saveSettings(settings: Partial<SettingsModel>): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.SaveSettings(JSON.stringify(settings));
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('SAVE_SETTINGS', 'SETTINGS_SAVED', { settings });
    }
  }


  public async getJobReportDetail(idx: number): Promise<ApiResponse<JobReportItem>> {
    if (isWebView && machine) {
      const result = await machine.Jobreport_GetDetail(idx);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse<JobReportItem>>('JOBREPORT_GET_DETAIL', 'JOBREPORT_DETAIL_DATA', { idx });
    }
  }

  public async addJobReport(
    pdate: string, projectName: string, pidx: number | null, requestpart: string, package_: string,
    type: string, process: string, status: string, description: string,
    hrs: number, ot: number, jobgrp: string, tag: string, otStart: string, otEnd: string
  ): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.Jobreport_Add(pdate, projectName, pidx ?? -1, requestpart, package_, type, process, status, description, hrs, ot, jobgrp, tag, otStart, otEnd);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('JOBREPORT_ADD', 'JOBREPORT_ADDED', {
        pdate, projectName, pidx: pidx ?? -1, requestpart, package: package_, jobType: type, process, status, description, hrs, ot, jobgrp, tag, otStart, otEnd
      });
    }
  }

  public async editJobReport(
    idx: number, pdate: string, projectName: string, pidx: number | null, requestpart: string, package_: string,
    type: string, process: string, status: string, description: string,
    hrs: number, ot: number, jobgrp: string, tag: string, otStart: string, otEnd: string
  ): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.Jobreport_Edit(idx, pdate, projectName, pidx ?? -1, requestpart, package_, type, process, status, description, hrs, ot, jobgrp, tag, otStart, otEnd);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('JOBREPORT_EDIT', 'JOBREPORT_EDITED', {
        idx, pdate, projectName, pidx: pidx ?? -1, requestpart, package: package_, jobType: type, process, status, description, hrs, ot, jobgrp, tag, otStart, otEnd
      });
    }
  }

  public async deleteJobReport(idx: number): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.Jobreport_Delete(idx);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('JOBREPORT_DELETE', 'JOBREPORT_DELETED', { idx });
    }
  }

  public async getJobReportPermission(targetUserId: string): Promise<JobReportPermission> {
    if (isWebView && machine) {
      const result = await machine.Jobreport_GetPermission(targetUserId);
      return JSON.parse(result);
    } else {
      return this.wsRequest<JobReportPermission>('JOBREPORT_GET_PERMISSION', 'JOBREPORT_PERMISSION', { targetUserId });
    }
  }

  public async getLastJobReportByProject(pidx: number, projectName: string): Promise<ApiResponse<any>> {
    if (isWebView && machine) {
      const result = await machine.Jobreport_GetLastByProject(pidx, projectName);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse<any>>('JOBREPORT_GET_LAST_BY_PROJECT', 'JOBREPORT_LAST_BY_PROJECT', { pidx, projectName });
    }
  }

  public async getJobReportTypeList(sd: string, ed: string, uid: string = ''): Promise<ApiResponse<JobReportTypeItem[]>> {
    if (isWebView && machine) {
      const result = await machine.Jobreport_GetList(sd, ed, uid, '', '');
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse<JobReportTypeItem[]>>('JOBREPORT_GET_TYPE_LIST', 'JOBREPORT_TYPE_LIST_DATA', { sd, ed, uid });
    }
  }

  public async getJobTypes(process: string = ''): Promise<ApiResponse<JobTypeItem[]>> {
    if (isWebView && machine) {
      const result = await machine.Jobreport_GetJobTypes(process);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse<JobTypeItem[]>>('JOBREPORT_GET_JOBTYPES', 'JOBREPORT_JOBTYPES', { process });
    }
  }

  public async getAppVersion(): Promise<AppVersionInfo> {
    if (isWebView && machine) {
      const result = await machine.GetAppVersion();
      return JSON.parse(result);
    } else {
      return this.wsRequest<AppVersionInfo>('GET_APP_VERSION', 'APP_VERSION', {});
    }
  }

  // ===== Holiday API (월별근무표) =====

  public async getHolidayList(month: string): Promise<ApiResponse<HolidayItem[]>> {
    if (isWebView && machine) {
      const result = await machine.Holiday_GetList(month);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse<HolidayItem[]>>('HOLIDAY_GET_LIST', 'HOLIDAY_LIST_DATA', { month });
    }
  }

  public async saveHolidays(month: string, holidays: HolidayItem[]): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.Holiday_Save(month, JSON.stringify(holidays));
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('HOLIDAY_SAVE', 'HOLIDAY_SAVED', { month, holidays });
    }
  }

  public async initializeHoliday(month: string): Promise<ApiResponse<{ Created: boolean }>> {
    if (isWebView && machine) {
      const result = await machine.Holiday_Initialize(month);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse<{ Created: boolean }>>('HOLIDAY_INITIALIZE', 'HOLIDAY_INITIALIZED', { month });
    }
  }

  // ===== HolidayRequest API (휴가/외출 신청) =====

  public async getHolidayRequestList(startDate: string, endDate: string, userId: string, userLevel: number): Promise<ApiResponse<HolidayRequest[]>> {
    if (isWebView && machine) {
      const result = await machine.HolidayRequest_GetList(startDate, endDate, userId, userLevel);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse<HolidayRequest[]>>('HOLIDAY_REQUEST_GET_LIST', 'HOLIDAY_REQUEST_LIST_DATA', { startDate, endDate, userId, userLevel });
    }
  }

  public async saveHolidayRequest(data: HolidayRequest): Promise<ApiResponse> {
    const { idx, uid, cate, sdate, edate, Remark, Response, conf, HolyReason, HolyBackup, HolyLocation, HolyDays, HolyTimes, stime, etime } = data;
    const remark = Remark || '';
    const response = Response || '';
    const holyReason = HolyReason || '';
    const holyBackup = HolyBackup || '';
    const holyLocation = HolyLocation || '';
    const holyDays = HolyDays || 0;
    const holyTimes = HolyTimes || 0;
    const sTime = stime || '';
    const eTime = etime || '';

    if (isWebView && machine) {
      const result = await machine.HolidayRequest_Save(idx, uid, cate, sdate, edate, remark, response, conf, holyReason, holyBackup, holyLocation, holyDays, holyTimes, sTime, eTime);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('HOLIDAY_REQUEST_SAVE', 'HOLIDAY_REQUEST_SAVED', {
        idx, uid, cate, sdate, edate, remark, response, conf, holyReason, holyBackup, holyLocation, holyDays, holyTimes, stime: sTime, etime: eTime
      });
    }
  }

  // ===== MailForm API (메일양식) =====

  public async getMailFormList(): Promise<ApiResponse<MailFormItem[]>> {
    if (isWebView && machine) {
      const result = await machine.MailForm_GetList();
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse<MailFormItem[]>>('MAILFORM_GET_LIST', 'MAILFORM_LIST_DATA');
    }
  }

  public async getMailFormDetail(idx: number): Promise<ApiResponse<MailFormItem>> {
    if (isWebView && machine) {
      const result = await machine.MailForm_GetDetail(idx);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse<MailFormItem>>('MAILFORM_GET_DETAIL', 'MAILFORM_DETAIL_DATA', { idx });
    }
  }

  public async addMailForm(
    cate: string, title: string, tolist: string, bcc: string, cc: string,
    subject: string, tail: string, body: string, selfTo: boolean, selfCC: boolean,
    selfBCC: boolean, exceptmail: string, exceptmailcc: string
  ): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.MailForm_Add(cate, title, tolist, bcc, cc, subject, tail, body, selfTo, selfCC, selfBCC, exceptmail, exceptmailcc);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('MAILFORM_ADD', 'MAILFORM_ADDED', {
        cate, title, tolist, bcc, cc, subject, tail, body, selfTo, selfCC, selfBCC, exceptmail, exceptmailcc
      });
    }
  }

  public async editMailForm(
    idx: number, cate: string, title: string, tolist: string, bcc: string, cc: string,
    subject: string, tail: string, body: string, selfTo: boolean, selfCC: boolean,
    selfBCC: boolean, exceptmail: string, exceptmailcc: string
  ): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.MailForm_Edit(idx, cate, title, tolist, bcc, cc, subject, tail, body, selfTo, selfCC, selfBCC, exceptmail, exceptmailcc);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('MAILFORM_EDIT', 'MAILFORM_EDITED', {
        idx, cate, title, tolist, bcc, cc, subject, tail, body, selfTo, selfCC, selfBCC, exceptmail, exceptmailcc
      });
    }
  }

  public async deleteMailForm(idx: number): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.MailForm_Delete(idx);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('MAILFORM_DELETE', 'MAILFORM_DELETED', { idx });
    }
  }

  // ===== UserGroup API (그룹정보/권한설정) =====

  public async getUserGroupList(): Promise<ApiResponse<UserGroupItem[]>> {
    if (isWebView && machine) {
      const result = await machine.UserGroup_GetList();
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse<UserGroupItem[]>>('USERGROUP_GET_LIST', 'USERGROUP_LIST_DATA');
    }
  }

  public async addUserGroup(
    dept: string, path_kj: string, permission: number, advpurchase: boolean,
    advkisul: boolean, managerinfo: string, devinfo: string, usemail: boolean
  ): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.UserGroup_Add(dept, path_kj, permission, advpurchase, advkisul, managerinfo, devinfo, usemail);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('USERGROUP_ADD', 'USERGROUP_ADDED', {
        dept, path_kj, permission, advpurchase, advkisul, managerinfo, devinfo, usemail
      });
    }
  }

  public async editUserGroup(
    originalDept: string, dept: string, path_kj: string, permission: number,
    advpurchase: boolean, advkisul: boolean, managerinfo: string, devinfo: string, usemail: boolean
  ): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.UserGroup_Edit(originalDept, dept, path_kj, permission, advpurchase, advkisul, managerinfo, devinfo, usemail);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('USERGROUP_EDIT', 'USERGROUP_EDITED', {
        originalDept, dept, path_kj, permission, advpurchase, advkisul, managerinfo, devinfo, usemail
      });
    }
  }

  public async deleteUserGroup(dept: string): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.UserGroup_Delete(dept);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('USERGROUP_DELETE', 'USERGROUP_DELETED', { dept });
    }
  }

  public async getPermissionInfo(): Promise<ApiResponse<PermissionInfo[]>> {
    if (isWebView && machine) {
      const result = await machine.UserGroup_GetPermissionInfo();
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse<PermissionInfo[]>>('USERGROUP_GET_PERMISSION_INFO', 'USERGROUP_PERMISSION_INFO');
    }
  }

  // ===== UserAuth API (사용자 권한) =====

  public async userAuthCanAccess(): Promise<{ Success: boolean; CanAccess?: boolean; Level?: number; Message?: string }> {
    if (isWebView && machine) {
      const result = await machine.UserAuth_CanAccess();
      return JSON.parse(result);
    } else {
      return this.wsRequest<{ Success: boolean; CanAccess?: boolean; Level?: number; Message?: string }>('USERAUTH_CAN_ACCESS', 'USERAUTH_CAN_ACCESS_DATA');
    }
  }

  public async getUserAuthList(): Promise<ApiResponse<AuthItem[]>> {
    if (isWebView && machine) {
      const result = await machine.UserAuth_GetList();
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse<AuthItem[]>>('USERAUTH_GET_LIST', 'USERAUTH_LIST_DATA');
    }
  }

  public async saveUserAuth(
    idx: number, user: string, account: number, purchase: number, purchaseEB: number,
    holyday: number, project: number, jobreport: number, scheapp: number,
    equipment: number, otconfirm: number, holyreq: number, kuntae: number
  ): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.UserAuth_Save(idx, user, account, purchase, purchaseEB, holyday, project, jobreport, scheapp, equipment, otconfirm, holyreq, kuntae);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('USERAUTH_SAVE', 'USERAUTH_SAVED', {
        idx, user, account, purchase, purchaseEB, holyday, project, jobreport, scheapp, equipment, otconfirm, holyreq, kuntae
      });
    }
  }

  public async deleteUserAuth(idx: number): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.UserAuth_Delete(idx);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('USERAUTH_DELETE', 'USERAUTH_DELETED', { idx });
    }
  }

  public async getUserAuthFields(): Promise<ApiResponse<AuthFieldInfo[]>> {
    if (isWebView && machine) {
      const result = await machine.UserAuth_GetFields();
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse<AuthFieldInfo[]>>('USERAUTH_GET_FIELDS', 'USERAUTH_FIELDS_DATA');
    }
  }

  // ===== 범용 권한 체크 API =====

  /**
   * 범용 권한 체크 API
   * @param authType 권한 타입 (purchase, holyday, project, jobreport, account 등)
   * @param requiredLevel 필요한 최소 레벨 (기본값 5)
   * @returns CheckAuthResponse - CanAccess, UserLevel, AuthLevel, EffectiveLevel 등
   */
  public async checkAuth(authType: AuthType | string, requiredLevel: number = 5): Promise<CheckAuthResponse> {
    if (isWebView && machine) {
      const result = await machine.CheckAuth(authType, requiredLevel);
      return JSON.parse(result);
    } else {
      return this.wsRequest<CheckAuthResponse>('CHECK_AUTH', 'CHECK_AUTH_DATA', { authType, requiredLevel });
    }
  }

  /**
   * 현재 로그인한 사용자의 전체 권한 정보 조회
   * @returns ApiResponse<MyAuthInfo> - 사용자 레벨 및 각 항목별 권한 레벨
   */
  public async getMyAuth(): Promise<ApiResponse<MyAuthInfo>> {
    if (isWebView && machine) {
      const result = await machine.GetMyAuth();
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse<MyAuthInfo>>('GET_MY_AUTH', 'MY_AUTH_DATA');
    }
  }

  // ===== 프로젝트 검색 API (업무일지용) =====

  /**
   * 프로젝트 검색 (Projects 테이블 + 과거 업무일지 항목명)
   * @param keyword 검색어
   * @returns ApiResponse<ProjectSearchItem[]>
   */
  public async searchProjects(keyword: string): Promise<ApiResponse<ProjectSearchItem[]>> {
    if (isWebView && machine) {
      const result = await machine.Project_Search(keyword);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse<ProjectSearchItem[]>>('PROJECT_SEARCH', 'PROJECT_SEARCH_DATA', { keyword });
    }
  }

  /**
   * 현재 사용자의 프로젝트 목록 조회 (업무일지 콤보박스용)
   * @returns ApiResponse<{idx: number, name: string, status: string}[]>
   */
  public async getUserProjects(): Promise<ApiResponse<{ idx: number, name: string, status: string }[]>> {
    if (isWebView && machine) {
      const result = await machine.Project_GetUserProjects();
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse<{ idx: number, name: string, status: string }[]>>('PROJECT_GET_USER_PROJECTS', 'PROJECT_USER_PROJECTS_DATA');
    }
  }

  // ===== Note API (메모장) =====

  /**
   * 메모장 목록 조회
   * @param startDate 시작일 (yyyy-MM-dd)
   * @param endDate 종료일 (yyyy-MM-dd)
   * @param uid 사용자 ID (빈 문자열이면 전체)
   * @returns ApiResponse<NoteItem[]>
   */
  public async getNoteList(startDate: string, endDate: string, uid: string = ''): Promise<ApiResponse<NoteItem[]>> {
    if (isWebView && machine) {
      const result = await machine.Note_GetList(startDate, endDate, uid);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse<NoteItem[]>>('NOTE_GET_LIST', 'NOTE_LIST_DATA', { startDate, endDate, uid });
    }
  }

  /**
   * 메모장 상세 조회
   * @param idx 메모 인덱스
   * @returns ApiResponse<NoteItem>
   */
  public async getNoteDetail(idx: number): Promise<ApiResponse<NoteItem>> {
    if (isWebView && machine) {
      const result = await machine.Note_GetDetail(idx);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse<NoteItem>>('NOTE_GET_DETAIL', 'NOTE_DETAIL_DATA', { idx });
    }
  }

  /**
   * 메모장 추가
   * @param pdate 날짜 (yyyy-MM-dd)
   * @param title 제목
   * @param uid 작성자 ID
   * @param description 내용 (plain text)
   * @param description2 내용 (RTF - not used in web)
   * @param share 공유 여부
   * @param guid 폴더 GUID (빈 문자열이면 자동 생성)
   * @returns ApiResponse with new Idx
   */
  public async addNote(
    pdate: string,
    title: string,
    uid: string,
    description: string,
    description2: string = '',
    share: boolean = false,
    guid: string = ''
  ): Promise<ApiResponse<{ Idx: number }>> {
    if (isWebView && machine) {
      const result = await machine.Note_Add(pdate, title, uid, description, description2, share, guid);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse<{ Idx: number }>>('NOTE_ADD', 'NOTE_ADDED', {
        pdate, title, uid, description, description2, share, guid
      });
    }
  }

  /**
   * 메모장 수정
   * @param idx 메모 인덱스
   * @param pdate 날짜 (yyyy-MM-dd)
   * @param title 제목
   * @param uid 작성자 ID
   * @param description 내용 (plain text)
   * @param description2 내용 (RTF - not used in web)
   * @param share 공유 여부
   * @param guid 폴더 GUID
   * @returns ApiResponse
   */
  public async editNote(
    idx: number,
    pdate: string,
    title: string,
    uid: string,
    description: string,
    description2: string = '',
    share: boolean = false,
    guid: string = ''
  ): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.Note_Edit(idx, pdate, title, uid, description, description2, share, guid);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('NOTE_EDIT', 'NOTE_EDITED', {
        idx, pdate, title, uid, description, description2, share, guid
      });
    }
  }

  /**
   * 메모장 삭제
   * @param idx 메모 인덱스
   * @returns ApiResponse
   */
  public async deleteNote(idx: number): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.Note_Delete(idx);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('NOTE_DELETE', 'NOTE_DELETED', { idx });
    }
  }

  /**
   * 게시판 목록 조회
   * @param bidx 게시판 인덱스 (5=패치내역)
   * @param searchKey 검색어
   * @returns ApiResponse<BoardItem[]>
   */
  public async getBoardList(bidx: number, searchKey: string = ''): Promise<ApiResponse<BoardItem[]>> {
    if (isWebView && machine) {
      const result = await machine.Board_GetList(bidx, searchKey);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse<BoardItem[]>>('BOARD_GET_LIST', 'BOARD_LIST_DATA', { bidx, searchKey });
    }
  }

  /**
   * 게시판 상세 조회
   * @param idx 게시판 글 인덱스
   * @returns ApiResponse<BoardItem>
   */
  public async getBoardDetail(idx: number): Promise<ApiResponse<BoardItem>> {
    if (isWebView && machine) {
      const result = await machine.Board_GetDetail(idx);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse<BoardItem>>('BOARD_GET_DETAIL', 'BOARD_DETAIL_DATA', { idx });
    }
  }

  /**
   * 게시판 추가
   * @param bidx 게시판 인덱스
   * @param header 헤더
   * @param cate 카테고리
   * @param title 제목
   * @param contents 내용
   * @returns ApiResponse
   */
  public async addBoard(bidx: number, header: string, cate: string, title: string, contents: string): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.Board_Add(bidx, header, cate, title, contents);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('BOARD_ADD', 'BOARD_ADDED', { bidx, header, cate, title, contents });
    }
  }

  /**
   * 게시판 수정
   * @param idx 게시판 글 인덱스
   * @param header 헤더
   * @param cate 카테고리
   * @param title 제목
   * @param contents 내용
   * @returns ApiResponse
   */
  public async editBoard(idx: number, header: string, cate: string, title: string, contents: string): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.Board_Edit(idx, header, cate, title, contents);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('BOARD_EDIT', 'BOARD_EDITED', { idx, header, cate, title, contents });
    }
  }

  /**
   * 게시판 삭제
   * @param idx 게시판 글 인덱스
   * @returns ApiResponse
   */
  public async deleteBoard(idx: number): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.Board_Delete(idx);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('BOARD_DELETE', 'BOARD_DELETED', { idx });
    }
  }

  /**
   * 게시판 댓글/답글 목록 조회
   * @param rootIdx 원글 인덱스
   * @returns ApiResponse<BoardItem[]>
   */
  public async getBoardReplies(rootIdx: number): Promise<ApiResponse<BoardItem[]>> {
    if (isWebView && machine) {
      const result = await machine.Board_GetReplies(rootIdx);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse<BoardItem[]>>('BOARD_GET_REPLIES', 'BOARD_REPLIES_DATA', { rootIdx });
    }
  }

  /**
   * 게시판 댓글/답글 추가
   * @param rootIdx 원글 인덱스
   * @param pidx 부모 글 인덱스
   * @param contents 댓글 내용
   * @param isComment 댓글 타입 (true: 댓글, false: 답글)
   * @returns ApiResponse
   */
  public async addBoardReply(rootIdx: number, pidx: number, title: string, contents: string, isComment: boolean = true): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.Board_AddReply(rootIdx, pidx, title, contents, isComment);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('BOARD_ADD_REPLY', 'BOARD_REPLY_ADDED', { rootIdx, pidx, title, contents, isComment });
    }
  }

  /**
   * 메일 발신 내역 조회
   * @param startDate 시작일 (yyyy-MM-dd)
   * @param endDate 종료일 (yyyy-MM-dd)
   * @param searchKey 검색어
   * @returns ApiResponse<MailItem[]>
   */
  public async getMailList(startDate: string, endDate: string, searchKey: string = ''): Promise<ApiResponse<MailItem[]>> {
    if (isWebView && machine) {
      const result = await machine.Mail_GetList(startDate, endDate, searchKey);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse<MailItem[]>>('MAIL_GET_LIST', 'MAIL_LIST_DATA', { startDate, endDate, searchKey });
    }
  }

  /**
   * 메일 데이터 추가 (발송 대기열)
   * @param cate 분류
   * @param subject 제목
   * @param fromlist 발신자
   * @param tolist 수신자
   * @param cc 참조
   * @param bcc 숨은참조
   * @param body 내용
   * @returns ApiResponse
   */
  public async addMailData(cate: string, subject: string, fromlist: string, tolist: string, cc: string, bcc: string, body: string): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.Mail_AddData(cate, subject, fromlist, tolist, cc, bcc, body);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('MAIL_ADD_DATA', 'MAIL_ADD_DATA_RESULT', { cate, subject, fromlist, tolist, cc, bcc, body });
    }
  }

  /**
   * 메일 직접 발송 (SMTP)
   * @param cate 분류
   * @param subject 제목
   * @param fromlist 발신자
   * @param tolist 수신자
   * @param cc 참조
   * @param bcc 숨은참조
   * @param body 내용
   * @returns ApiResponse
   */
  public async sendMailDirect(cate: string, subject: string, fromlist: string, tolist: string, cc: string, bcc: string, body: string): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.Mail_SendDirect(cate, subject, fromlist, tolist, cc, bcc, body);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('MAIL_SEND_DIRECT', 'MAIL_SEND_DIRECT_RESULT', { cate, subject, fromlist, tolist, cc, bcc, body });
    }
  }

  /**
   * Outlook으로 메일 미리보기/발송
   * @param subject 제목
   * @param tolist 수신자
   * @param cc 참조
   * @param bcc 숨은참조
   * @param body 내용
   * @returns ApiResponse
   */
  public async sendMailOutlook(subject: string, tolist: string, cc: string, bcc: string, body: string): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.Mail_SendOutlook(subject, tolist, cc, bcc, body);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('MAIL_SEND_OUTLOOK', 'MAIL_SEND_OUTLOOK_RESULT', { subject, tolist, cc, bcc, body });
    }
  }

  /**
   * 업체정보 목록 조회
   * @param searchKey 검색어
   * @returns ApiResponse<CustomItem[]>
   */
  public async getCustomsList(searchKey: string = ''): Promise<ApiResponse<CustomItem[]>> {
    if (isWebView && machine) {
      const result = await machine.Customs_GetList(searchKey);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse<CustomItem[]>>('CUSTOMS_GET_LIST', 'CUSTOMS_LIST_DATA', { searchKey });
    }
  }

  /**
   * 업체정보 상세 조회
   * @param idx 업체 인덱스
   * @returns ApiResponse<CustomItem>
   */
  public async getCustomsDetail(idx: number): Promise<ApiResponse<CustomItem>> {
    if (isWebView && machine) {
      const result = await machine.Customs_GetDetail(idx);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse<CustomItem>>('CUSTOMS_GET_DETAIL', 'CUSTOMS_DETAIL_DATA', { idx });
    }
  }

  /**
   * 라이선스 목록 조회
   * @returns ApiResponse<LicenseItem[]>
   */
  public async getLicenseList(): Promise<ApiResponse<LicenseItem[]>> {
    if (isWebView && machine) {
      const result = await machine.License_GetList();
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse<LicenseItem[]>>('LICENSE_GET_LIST', 'LICENSE_LIST_DATA', {});
    }
  }

  /**
   * 라이선스 추가
   */
  public async addLicense(
    name: string,
    version: string,
    meterialNo: string,
    supply: string,
    qty: number,
    uids: string,
    serialNo: string,
    remark: string,
    sdate: string,
    edate: string,
    manu: string,
    expire: boolean
  ): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.License_Add(name, version, meterialNo, supply, qty, uids, serialNo, remark, sdate, edate, manu, expire);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('LICENSE_ADD', 'LICENSE_ADD_RESULT', {
        name, version, meterialNo, supply, qty, uids, serialNo, remark, sdate, edate, manu, expire
      });
    }
  }

  /**
   * 라이선스 수정
   */
  public async updateLicense(
    idx: number,
    name: string,
    version: string,
    meterialNo: string,
    supply: string,
    qty: number,
    uids: string,
    serialNo: string,
    remark: string,
    sdate: string,
    edate: string,
    manu: string,
    expire: boolean
  ): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.License_Update(idx, name, version, meterialNo, supply, qty, uids, serialNo, remark, sdate, edate, manu, expire);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('LICENSE_UPDATE', 'LICENSE_UPDATE_RESULT', {
        idx, name, version, meterialNo, supply, qty, uids, serialNo, remark, sdate, edate, manu, expire
      });
    }
  }

  /**
   * 라이선스 삭제
   */
  public async deleteLicense(idx: number): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.License_Delete(idx);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('LICENSE_DELETE', 'LICENSE_DELETE_RESULT', { idx });
    }
  }

  /**
   * 라이선스 폴더 열기
   */
  public async openLicenseFolder(idx: number): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.License_OpenFolder(idx);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('LICENSE_OPEN_FOLDER', 'LICENSE_OPEN_FOLDER_RESULT', { idx });
    }
  }

  /**
   * 라이선스 CSV 내보내기
   */
  public async exportLicenseCSV(filePath: string): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.License_ExportCSV(filePath);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('LICENSE_EXPORT_CSV', 'LICENSE_EXPORT_CSV_RESULT', { filePath });
    }
  }

  // ===== PartList API =====

  /**
   * 프로젝트별 파트리스트 조회
   */
  public async getPartList(projectIdx: number): Promise<ApiResponse<PartListItem[]>> {
    if (isWebView && machine) {
      const result = await machine.PartList_GetList(projectIdx);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse<PartListItem[]>>('PARTLIST_GET_LIST', 'PARTLIST_LIST_DATA', { projectIdx });
    }
  }

  /**
   * 파트리스트 항목 저장 (추가/수정)
   */
  public async savePartList(
    idx: number,
    projectIdx: number,
    itemgroup: string,
    itemname: string,
    item: string,
    itemmodel: string,
    itemscale: string,
    itemunit: string,
    qty: number,
    price: number,
    itemsupply: string,
    itemsupplyidx: number,
    itemmanu: string,
    itemsid: string,
    option1: string,
    remark: string,
    no: number,
    qtybuy: number
  ): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.PartList_Save(
        idx, projectIdx, itemgroup, itemname, item, itemmodel, itemscale,
        itemunit, qty, price, itemsupply, itemsupplyidx, itemmanu, itemsid,
        option1, remark, no, qtybuy
      );
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('PARTLIST_SAVE', 'PARTLIST_SAVE_RESULT', {
        idx, projectIdx, itemgroup, itemname, item, itemmodel, itemscale,
        itemunit, qty, price, itemsupply, itemsupplyidx, itemmanu, itemsid,
        option1, remark, no, qtybuy
      });
    }
  }

  /**
   * 파트리스트 항목 삭제
   */
  public async deletePartList(idx: number): Promise<ApiResponse> {
    if (isWebView && machine) {
      const result = await machine.PartList_Delete(idx);
      return JSON.parse(result);
    } else {
      return this.wsRequest<ApiResponse>('PARTLIST_DELETE', 'PARTLIST_DELETE_RESULT', { idx });
    }
  }
}

export const comms = new CommunicationLayer();
