/**
 * ============================================================================
 * 通用工具函数库
 * ============================================================================
 */

/**
 * 模态框控制器
 */
const Modal = {
  overlay: null,
  currentOnConfirm: null,

  /**
   * 初始化模态框
   */
  init() {
    this.overlay = document.createElement('div');
    this.overlay.className = 'modal-overlay';
    this.overlay.id = 'global-modal-overlay';
    document.body.appendChild(this.overlay);
  },

  /**
   * 显示模态框
   * @param {Object} options - 配置选项
   * @param {string} options.title - 标题
   * @param {string} options.content - HTML内容
   * @param {Function} options.onConfirm - 确认回调
   * @param {Function} options.onCancel - 取消回调
   * @param {boolean} options.showCancel - 是否显示取消按钮
   * @param {string} options.confirmText - 确认按钮文字
   * @param {string} options.cancelText - 取消按钮文字
   * @param {boolean} options.danger - 危险操作(红色按钮)
   */
  show(options) {
    if (!this.overlay) this.init();

    const {
      title = '提示',
      content = '',
      onConfirm = null,
      onCancel = null,
      showCancel = true,
      confirmText = '确认',
      cancelText = '取消',
      danger = false
    } = options;

    this.currentOnConfirm = onConfirm;

    const confirmBtnClass = danger ? 'btn btn-danger' : 'btn btn-primary';

    this.overlay.innerHTML = `
      <div class="modal">
        <div class="modal-header">
          <h3 class="modal-title">${title}</h3>
          <button class="modal-close" data-action="close">&times;</button>
        </div>
        <div class="modal-body">${content}</div>
        <div class="modal-footer">
          ${showCancel ? `<button class="btn btn-secondary" data-action="cancel">${cancelText}</button>` : ''}
          <button class="${confirmBtnClass}" data-action="confirm">${confirmText}</button>
        </div>
      </div>
    `;

    // 绑定事件
    this.overlay.addEventListener('click', (e) => {
      const action = e.target.dataset.action;

      if (action === 'close' || e.target === this.overlay) {
        this.hide();
        if (onCancel) onCancel();
      } else if (action === 'cancel') {
        this.hide();
        if (onCancel) onCancel();
      } else if (action === 'confirm') {
        let shouldClose = true;
        if (this.currentOnConfirm) {
          shouldClose = this.currentOnConfirm() !== false;
        }
        if (shouldClose) {
          this.hide();
        }
      }
    }, { once: true });

    this.overlay.classList.add('active');
  },

  /**
   * 隐藏模态框
   */
  hide() {
    if (this.overlay) {
      this.overlay.classList.remove('active');
    }
  },

  /**
   * 显示确认对话框
   * @param {string} message - 确认消息
   * @param {Function} onConfirm - 确认回调
   * @param {string} title - 标题
   */
  confirm(message, onConfirm, title = '确认') {
    this.show({
      title,
      content: `<p class="text-secondary">${message}</p>`,
      onConfirm,
      danger: true
    });
  },

  /**
   * 显示提示对话框
   * @param {string} message - 提示消息
   * @param {Function} onConfirm - 确认回调
   * @param {string} title - 标题
   */
  alert(message, onConfirm = null, title = '提示') {
    this.show({
      title,
      content: `<p class="text-secondary">${message}</p>`,
      onConfirm,
      showCancel: false
    });
  }
};

/**
 * Toast 消息提示
 */
const Toast = {
  container: null,
  queue: [],
  isShowing: false,

  /**
   * 初始化
   */
  init() {
    this.container = document.createElement('div');
    this.container.className = 'toast-container';
    document.body.appendChild(this.container);
  },

  /**
   * 显示提示
   * @param {string} message - 消息内容
   * @param {string} type - 类型: 'success' | 'error' | 'warning'
   * @param {number} duration - 显示时长(ms)
   */
  show(message, type = 'success', duration = 3000) {
    if (!this.container) this.init();

    const icons = {
      success: '✓',
      error: '✕',
      warning: '⚠'
    };

    const toast = document.createElement('div');
    toast.className = `toast ${type}`;
    toast.innerHTML = `
      <span class="toast-icon">${icons[type]}</span>
      <span class="toast-content">${message}</span>
    `;

    this.container.appendChild(toast);

    // 动画结束后自动移除
    setTimeout(() => {
      toast.style.opacity = '0';
      toast.style.transform = 'translateX(120%)';
      setTimeout(() => {
        toast.remove();
      }, 200);
    }, duration);
  },

  success(message, duration) {
    this.show(message, 'success', duration);
  },

  error(message, duration) {
    this.show(message, 'error', duration);
  },

  warning(message, duration) {
    this.show(message, 'warning', duration);
  }
};

/**
 * 表单验证器
 */
const Validator = {
  /**
   * 验证非空
   * @param {*} value - 值
   * @param {string} fieldName - 字段名
   * @returns {Object} { valid: boolean, message: string }
   */
  required(value, fieldName) {
    if (!value || value.toString().trim() === '') {
      return { valid: false, message: `${fieldName}不能为空` };
    }
    return { valid: true };
  },

  /**
   * 验证最小长度
   * @param {string} value - 值
   * @param {number} min - 最小长度
   * @param {string} fieldName - 字段名
   * @returns {Object} { valid: boolean, message: string }
   */
  minLength(value, min, fieldName) {
    if (value && value.length < min) {
      return { valid: false, message: `${fieldName}至少需要${min}个字符` };
    }
    return { valid: true };
  },

  /**
   * 验证最大长度
   * @param {string} value - 值
   * @param {number} max - 最大长度
   * @param {string} fieldName - 字段名
   * @returns {Object} { valid: boolean, message: string }
   */
  maxLength(value, max, fieldName) {
    if (value && value.length > max) {
      return { valid: false, message: `${fieldName}不能超过${max}个字符` };
    }
    return { valid: true };
  },

  /**
   * 验证URL格式
   * @param {string} url - URL
   * @returns {Object} { valid: boolean, message: string }
   */
  url(url) {
    if (!url || url.trim() === '') {
      return { valid: true }; // 允许为空
    }
    try {
      new URL(url);
      return { valid: true };
    } catch {
      return { valid: false, message: 'URL格式不正确' };
    }
  },

  /**
   * 验证邮箱格式
   * @param {string} email - 邮箱
   * @returns {Object} { valid: boolean, message: string }
   */
  email(email) {
    if (!email || email.trim() === '') {
      return { valid: true }; // 允许为空
    }
    const pattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    if (!pattern.test(email)) {
      return { valid: false, message: '邮箱格式不正确' };
    }
    return { valid: true };
  },

  /**
   * 验证IP地址
   * @param {string} ip - IP地址
   * @returns {Object} { valid: boolean, message: string }
   */
  ip(ip) {
    if (!ip || ip.trim() === '') {
      return { valid: true }; // 允许为空
    }
    const pattern = /^(\d{1,3}\.){3}\d{1,3}$/;
    if (!pattern.test(ip)) {
      return { valid: false, message: 'IP地址格式不正确' };
    }
    const parts = ip.split('.');
    if (parts.some(part => parseInt(part) > 255)) {
      return { valid: false, message: 'IP地址不正确' };
    }
    return { valid: true };
  },

  /**
   * 验证端口号
   * @param {number|string} port - 端口号
   * @returns {Object} { valid: boolean, message: string }
   */
  port(port) {
    const num = parseInt(port);
    if (!port || isNaN(num) || num < 1 || num > 65535) {
      return { valid: false, message: '端口号必须在 1-65535 之间' };
    }
    return { valid: true };
  },

  /**
   * 验证表单
   * @param {Object} rules - 验证规则 { fieldName: [{ rule, value, name }] }
   * @returns {Object} { valid: boolean, errors: Object }
   */
  validate(rules) {
    const errors = {};
    let valid = true;

    for (const [field, ruleList] of Object.entries(rules)) {
      for (const rule of ruleList) {
        const { rule: validator, value, name } = rule;
        const result = validator(value, name);
        if (!result.valid) {
          errors[field] = result.message;
          valid = false;
          break;
        }
      }
    }

    return { valid, errors };
  },

  /**
   * 显示表单错误
   * @param {Object} errors - 错误对象
   * @param {string} prefix - 字段ID前缀
   */
  showErrors(errors, prefix = '') {
    for (const [field, message] of Object.entries(errors)) {
      const element = document.getElementById(prefix + field);
      if (element) {
        element.classList.add('error');
        // 可以添加错误提示元素
      }
      Toast.error(message);
    }
  },

  /**
   * 清除表单错误
   * @param {string} prefix - 字段ID前缀
   */
  clearErrors(prefix = '') {
    const elements = document.querySelectorAll('[id^="' + prefix + '"].error');
    elements.forEach(el => el.classList.remove('error'));
  }
};

/**
 * 工具函数
 */
const Utils = {
  /**
   * 防抖
   * @param {Function} fn - 函数
   * @param {number} delay - 延迟时间(ms)
   * @returns {Function} 防抖后的函数
   */
  debounce(fn, delay = 300) {
    let timer = null;
    return function(...args) {
      clearTimeout(timer);
      timer = setTimeout(() => fn.apply(this, args), delay);
    };
  },

  /**
   * 节流
   * @param {Function} fn - 函数
   * @param {number} delay - 延迟时间(ms)
   * @returns {Function} 节流后的函数
   */
  throttle(fn, delay = 300) {
    let lastTime = 0;
    return function(...args) {
      const now = Date.now();
      if (now - lastTime >= delay) {
        lastTime = now;
        fn.apply(this, args);
      }
    };
  },

  /**
   * 生成唯一ID
   * @returns {string} 唯一ID
   */
  generateId() {
    return Date.now().toString(36) + Math.random().toString(36).substr(2, 9);
  },

  /**
   * 格式化日期
   * @param {Date|string} date - 日期对象或字符串
   * @param {string} format - 格式: 'datetime' | 'date' | 'time'
   * @returns {string} 格式化后的日期字符串
   */
  formatDate(date, format = 'datetime') {
    const d = new Date(date);
    const year = d.getFullYear();
    const month = String(d.getMonth() + 1).padStart(2, '0');
    const day = String(d.getDate()).padStart(2, '0');
    const hours = String(d.getHours()).padStart(2, '0');
    const minutes = String(d.getMinutes()).padStart(2, '0');
    const seconds = String(d.getSeconds()).padStart(2, '0');

    if (format === 'date') {
      return `${year}-${month}-${day}`;
    }
    if (format === 'time') {
      return `${hours}:${minutes}:${seconds}`;
    }
    return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
  },

  /**
   * 相对时间
   * @param {Date|string} date - 日期
   * @returns {string} 相对时间字符串
   */
  relativeTime(date) {
    const d = new Date(date);
    const now = new Date();
    const diff = Math.floor((now - d) / 1000);

    if (diff < 60) return '刚刚';
    if (diff < 3600) return `${Math.floor(diff / 60)}分钟前`;
    if (diff < 86400) return `${Math.floor(diff / 3600)}小时前`;
    if (diff < 604800) return `${Math.floor(diff / 86400)}天前`;
    return this.formatDate(date, 'date');
  },

  /**
   * 格式化文件大小
   * @param {number} bytes - 字节数
   * @returns {string} 格式化后的大小
   */
  formatFileSize(bytes) {
    if (bytes === 0) return '0 B';
    const k = 1024;
    const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
    const i = Math.floor(Math.log(bytes) / Math.log(k));
    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
  },

  /**
   * 复制到剪贴板
   * @param {string} text - 要复制的文本
   * @returns {Promise<boolean>} 是否成功
   */
  async copyToClipboard(text) {
    try {
      await navigator.clipboard.writeText(text);
      Toast.success('已复制到剪贴板');
      return true;
    } catch (e) {
      console.error('Copy to clipboard failed:', e);
      Toast.error('复制失败');
      return false;
    }
  },

  /**
   * 安全解析 JSON
   * @param {string} str - JSON字符串
   * @param {*} defaultValue - 默认值
   * @returns {*} 解析结果
   */
  safeJsonParse(str, defaultValue = null) {
    try {
      return JSON.parse(str);
    } catch (e) {
      return defaultValue;
    }
  },

  /**
   * 搜索过滤
   * @param {Array} items - 数据项数组
   * @param {string} query - 搜索关键词
   * @param {Array} fields - 要搜索的字段
   * @returns {Array} 过滤后的数组
   */
  filterItems(items, query, fields) {
    if (!query || query.trim() === '') {
      return items;
    }

    const lowerQuery = query.toLowerCase();
    return items.filter(item => {
      return fields.some(field => {
        const value = item[field];
        return value && value.toString().toLowerCase().includes(lowerQuery);
      });
    });
  },

  /**
   * 深拷贝对象
   * @param {*} obj - 要拷贝的对象
   * @returns {*} 拷贝后的对象
   */
  deepClone(obj) {
    if (obj === null || typeof obj !== 'object') return obj;
    if (obj instanceof Date) return new Date(obj.getTime());
    if (obj instanceof Array) return obj.map(item => this.deepClone(item));

    const cloned = {};
    for (const key in obj) {
      if (obj.hasOwnProperty(key)) {
        cloned[key] = this.deepClone(obj[key]);
      }
    }
    return cloned;
  },

  /**
   * URL参数解析
   * @param {string} url - URL字符串
   * @returns {Object} 参数对象
   */
  parseUrlParams(url = window.location.href) {
    const params = {};
    const queryString = url.split('?')[1];
    if (!queryString) return params;

    queryString.split('&').forEach(param => {
      const [key, value] = param.split('=');
      params[decodeURIComponent(key)] = decodeURIComponent(value || '');
    });

    return params;
  },

  /**
   * 构建URL参数
   * @param {Object} params - 参数对象
   * @returns {string} URL参数字符串
   */
  buildUrlParams(params) {
    return Object.keys(params)
      .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`)
      .join('&');
  },

  /**
   * 获取元素位置
   * @param {HTMLElement} element - DOM元素
   * @returns {Object} 位置信息
   */
  getElementPosition(element) {
    const rect = element.getBoundingClientRect();
    return {
      top: rect.top + window.pageYOffset,
      left: rect.left + window.pageXOffset,
      width: rect.width,
      height: rect.height
    };
  },

  /**
   * 平滑滚动到元素
   * @param {HTMLElement|string} element - DOM元素或选择器
   * @param {number} offset - 偏移量
   */
  scrollToElement(element, offset = 0) {
    const el = typeof element === 'string' ? document.querySelector(element) : element;
    if (!el) return;

    const position = this.getElementPosition(el);
    window.scrollTo({
      top: position.top - offset,
      behavior: 'smooth'
    });
  },

  /**
   * 下载文件
   * @param {string} content - 文件内容
   * @param {string} filename - 文件名
   * @param {string} type - MIME类型
   */
  downloadFile(content, filename, type = 'text/plain') {
    const blob = new Blob([content], { type });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = filename;
    a.click();
    URL.revokeObjectURL(url);
  }
};

/**
 * DOM 工具
 */
const DOM = {
  /**
   * 查询元素
   * @param {string} selector - 选择器
   * @param {HTMLElement} parent - 父元素
   * @returns {HTMLElement|null} DOM元素
   */
  $(selector, parent = document) {
    return parent.querySelector(selector);
  },

  /**
   * 查询所有元素
   * @param {string} selector - 选择器
   * @param {HTMLElement} parent - 父元素
   * @returns {NodeList} DOM元素列表
   */
  $$(selector, parent = document) {
    return parent.querySelectorAll(selector);
  },

  /**
   * 创建元素
   * @param {string} tag - 标签名
   * @param {Object} attributes - 属性对象
   * @param {string} content - 内容
   * @returns {HTMLElement} DOM元素
   */
  create(tag, attributes = {}, content = '') {
    const element = document.createElement(tag);

    for (const [key, value] of Object.entries(attributes)) {
      if (key === 'className') {
        element.className = value;
      } else if (key === 'style' && typeof value === 'object') {
        Object.assign(element.style, value);
      } else if (key.startsWith('on') && typeof value === 'function') {
        element.addEventListener(key.slice(2).toLowerCase(), value);
      } else {
        element.setAttribute(key, value);
      }
    }

    if (content) {
      element.innerHTML = content;
    }

    return element;
  },

  /**
   * 添加类名
   * @param {HTMLElement} element - DOM元素
   * @param {string} className - 类名
   */
  addClass(element, className) {
    element.classList.add(className);
  },

  /**
   * 移除类名
   * @param {HTMLElement} element - DOM元素
   * @param {string} className - 类名
   */
  removeClass(element, className) {
    element.classList.remove(className);
  },

  /**
   * 切换类名
   * @param {HTMLElement} element - DOM元素
   * @param {string} className - 类名
   * @param {boolean} force - 强制添加/移除
   */
  toggleClass(element, className, force) {
    element.classList.toggle(className, force);
  },

  /**
   * 设置/获取属性
   * @param {HTMLElement} element - DOM元素
   * @param {string} name - 属性名
   * @param {*} value - 属性值
   * @returns {string|undefined} 属性值
   */
  attr(element, name, value) {
    if (value === undefined) {
      return element.getAttribute(name);
    }
    element.setAttribute(name, value);
  }
};

// 导出到全局
window.Modal = Modal;
window.Toast = Toast;
window.Validator = Validator;
window.Utils = Utils;
window.DOM = DOM;