/**
 * ProfileScene.js
 * Player profile editing scene.
 * Supports nickname, signature, description editing and avatar upload.
 * All user-generated content is checked against content security before saving.
 */

const {
  SCREEN_WIDTH,
  SCREEN_HEIGHT,
  COLORS,
  SCENE,
} = require('../base/GameGlobal');
const { t } = require('../i18n/I18n');
const ContentSecurityManager = require('../managers/ContentSecurityManager');

// ============================================================
// Layout Constants
// ============================================================
const CENTER_X = SCREEN_WIDTH / 2;
const INPUT_WIDTH = Math.min(SCREEN_WIDTH * 0.7, 280);
const INPUT_HEIGHT = 36;
const BTN_WIDTH = Math.min(SCREEN_WIDTH * 0.5, 200);
const BTN_HEIGHT = 36;

// Field constraints
const NICKNAME_MIN = 2;
const NICKNAME_MAX = 20;
const SIGNATURE_MAX = 50;
const DESCRIPTION_MAX = 200;

// Profile field IDs
const FIELD = {
  NICKNAME: 'nickname',
  SIGNATURE: 'signature',
  DESCRIPTION: 'description',
  AVATAR: 'avatar',
};

// ============================================================
// Profile Scene
// ============================================================
const ProfileScene = {
  // Current editing state
  _editingField: null,       // Which field is being edited
  _inputText: '',            // Current input text
  _originalText: '',         // Original text before editing (for change detection)
  _errorMessage: '',         // Error message to display
  _isSubmitting: false,      // Whether a submission is in progress
  _localViolation: false,    // Whether local check found violation

  // User profile data
  _profile: {
    nickname: '',
    signature: '',
    description: '',
    avatarUrl: '',
  },

  // Open ID for API calls
  _openid: '',

  // Button rects for touch handling
  _backBtnRect: null,
  _nicknameRect: null,
  _signatureRect: null,
  _descriptionRect: null,
  _avatarRect: null,
  _saveBtnRect: null,
  _cancelBtnRect: null,

  enter() {
    this._editingField = null;
    this._inputText = '';
    this._errorMessage = '';
    this._isSubmitting = false;
    this._localViolation = false;

    // Load profile from storage
    this._loadProfile();

    // Get openid
    try {
      this._openid = wx.getStorageSync('player_openid') || '';
    } catch (e) {
      this._openid = '';
    }

    // Calculate button positions
    this._backBtnRect = { x: 10, y: 10, w: 60, h: 30 };
    this._avatarRect = {
      x: CENTER_X - 40,
      y: 70,
      w: 80,
      h: 80,
    };
    this._nicknameRect = {
      x: CENTER_X - INPUT_WIDTH / 2,
      y: 175,
      w: INPUT_WIDTH,
      h: INPUT_HEIGHT,
    };
    this._signatureRect = {
      x: CENTER_X - INPUT_WIDTH / 2,
      y: 240,
      w: INPUT_WIDTH,
      h: INPUT_HEIGHT,
    };
    this._descriptionRect = {
      x: CENTER_X - INPUT_WIDTH / 2,
      y: 305,
      w: INPUT_WIDTH,
      h: 80,
    };
    this._saveBtnRect = {
      x: CENTER_X - BTN_WIDTH / 2,
      y: SCREEN_HEIGHT - 100,
      w: BTN_WIDTH,
      h: BTN_HEIGHT,
    };
  },

  exit() {
    // Save profile to storage
    this._saveProfile();
  },

  update(dt) {},

  render(ctx) {
    // Background
    ctx.fillStyle = COLORS.MENU_BG;
    ctx.fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);

    const cx = CENTER_X;

    // Back button
    this._renderBackButton(ctx);

    // Title
    ctx.fillStyle = COLORS.MENU_TITLE;
    ctx.font = 'bold 24px Arial';
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
    ctx.fillText(t('profile.title'), cx, 50);

    // Avatar
    this._renderAvatar(ctx);

    // Nickname field
    this._renderField(ctx, this._nicknameRect, t('profile.nickname'), this._profile.nickname, FIELD.NICKNAME);

    // Signature field
    this._renderField(ctx, this._signatureRect, t('profile.signature'), this._profile.signature, FIELD.SIGNATURE);

    // Description field
    this._renderDescriptionField(ctx);

    // Error message (only show when NOT editing to avoid overlap)
    if (this._errorMessage && !this._editingField) {
      ctx.fillStyle = '#FF4444';
      ctx.font = '12px Arial';
      ctx.textAlign = 'center';
      ctx.fillText(this._errorMessage, cx, SCREEN_HEIGHT - 140);
    }

    // Editing overlay (includes save/cancel buttons)
    if (this._editingField) {
      this._renderEditOverlay(ctx);
    }
  },

  handleTouch(type, e) {
    if (type !== 'touchstart') return;
    const touch = e.touches[0];
    const x = touch.clientX;
    const y = touch.clientY;

    // If editing, handle save/cancel in overlay
    if (this._editingField) {
      this._handleEditOverlayTouch(x, y);
      return;
    }

    // Back button
    if (this._hitTest(x, y, this._backBtnRect)) {
      const sm = GameGlobal.sceneManager;
      sm.switchTo(SCENE.MENU);
      return;
    }

    // Avatar click
    if (this._hitTest(x, y, this._avatarRect)) {
      this._handleChangeAvatar();
      return;
    }

    // Nickname click
    if (this._hitTest(x, y, this._nicknameRect)) {
      this._startEditing(FIELD.NICKNAME, this._profile.nickname);
      return;
    }

    // Signature click
    if (this._hitTest(x, y, this._signatureRect)) {
      this._startEditing(FIELD.SIGNATURE, this._profile.signature);
      return;
    }

    // Description click
    if (this._hitTest(x, y, this._descriptionRect)) {
      this._startEditing(FIELD.DESCRIPTION, this._profile.description);
      return;
    }
  },

  _startEditing(field, currentValue) {
    const csm = GameGlobal.contentSecurityManager;
    if (!csm || !csm.isInitialized()) return;

    this._editingField = field;
    this._inputText = currentValue || '';
    this._originalText = currentValue || '';
    this._errorMessage = '';
    this._localViolation = false;

    // Determine input constraints
    let maxLength = 200;
    if (field === FIELD.NICKNAME) maxLength = NICKNAME_MAX;
    if (field === FIELD.SIGNATURE) maxLength = SIGNATURE_MAX;
    if (field === FIELD.DESCRIPTION) maxLength = DESCRIPTION_MAX;

    // Show keyboard with empty defaultValue, so the native "Done" button highlights
    // as soon as user types any character. The original value is preserved in
    // _originalText and shown in the overlay preview for reference.
    wx.showKeyboard({
      defaultValue: '',
      maxLength,
      multiple: field === FIELD.DESCRIPTION,
      confirmHold: false,
      confirmType: 'done',
    });
    // Reset _inputText so we know if user actually typed something
    this._inputText = '';

    // Listen for keyboard input
    this._onKeyboardInput = (res) => {
      this._inputText = res.value || '';
      this._validateInput(field);
    };

    this._onKeyboardConfirm = (res) => {
      // Ensure we have the final value on confirm
      if (res && res.value !== undefined) {
        this._inputText = res.value;
      }
      this._validateInput(field);
      // Only auto-submit if no violations
      if (!this._localViolation) {
        this._handleSubmit();
      }
    };

    this._onKeyboardComplete = (res) => {
      // Keyboard closed - get final value
      if (res && res.value !== undefined) {
        this._inputText = res.value;
        this._validateInput(field);
      }
    };

    wx.onKeyboardInput(this._onKeyboardInput);
    wx.onKeyboardConfirm(this._onKeyboardConfirm);
    wx.onKeyboardComplete(this._onKeyboardComplete);

    // Initial validation to set correct button state
    this._validateInput(field);
  },

  _stopEditing() {
    if (this._onKeyboardInput) {
      wx.offKeyboardInput(this._onKeyboardInput);
      this._onKeyboardInput = null;
    }
    if (this._onKeyboardConfirm) {
      wx.offKeyboardConfirm(this._onKeyboardConfirm);
      this._onKeyboardConfirm = null;
    }
    if (this._onKeyboardComplete) {
      wx.offKeyboardComplete(this._onKeyboardComplete);
      this._onKeyboardComplete = null;
    }
    wx.hideKeyboard();
    this._editingField = null;
  },

  _validateInput(field) {
    const csm = GameGlobal.contentSecurityManager;
    const text = this._inputText || '';

    // Reset violation state first
    this._localViolation = false;
    this._errorMessage = '';

    // Empty check
    if (!text || text.trim().length === 0) {
      this._localViolation = true;
      this._errorMessage = '内容不能为空';
      return;
    }

    // Sensitive word check
    if (csm && csm.isInitialized()) {
      const localCheck = csm.checkLocalText(text);
      if (localCheck.hasViolation) {
        this._localViolation = true;
        this._errorMessage = '内容包含违规信息，请修改';
        return;
      }
    }

    // Length validation
    if (field === FIELD.NICKNAME) {
      if (text.length < NICKNAME_MIN) {
        this._localViolation = true;
        this._errorMessage = `昵称至少需要${NICKNAME_MIN}个字符`;
      } else if (text.length > NICKNAME_MAX) {
        this._localViolation = true;
        this._errorMessage = `昵称不能超过${NICKNAME_MAX}个字符`;
      }
    } else if (field === FIELD.SIGNATURE) {
      if (text.length > SIGNATURE_MAX) {
        this._localViolation = true;
        this._errorMessage = `签名不能超过${SIGNATURE_MAX}个字符`;
      }
    } else if (field === FIELD.DESCRIPTION) {
      if (text.length > DESCRIPTION_MAX) {
        this._localViolation = true;
        this._errorMessage = `描述不能超过${DESCRIPTION_MAX}个字符`;
      }
    }
  },

  async _handleSubmit() {
    if (this._isSubmitting || this._localViolation) return;

    const csm = GameGlobal.contentSecurityManager;
    if (!csm || !this._editingField) return;

    const content = this._inputText.trim();
    if (!content) {
      this._errorMessage = '内容不能为空';
      return;
    }

    this._isSubmitting = true;
    this._errorMessage = '审核中...';

    // Determine scene
    const sceneMap = {
      [FIELD.NICKNAME]: ContentSecurityManager.SCENE.NICKNAME,
      [FIELD.SIGNATURE]: ContentSecurityManager.SCENE.SIGNATURE,
      [FIELD.DESCRIPTION]: ContentSecurityManager.SCENE.DESCRIPTION,
    };
    const scene = sceneMap[this._editingField];

    // Full text check (local + server)
    const result = await csm.fullTextCheck(this._openid, content, scene);

    this._isSubmitting = false;

    if (result.pass) {
      // Save the content
      this._profile[this._editingField] = content;
      this._saveProfile();
      this._errorMessage = '';
      this._stopEditing();
    } else {
      this._errorMessage = result.errorMessage;
    }
  },

  // ============================================================
  // Avatar Upload
  // ============================================================

  _handleChangeAvatar() {
    const csm = GameGlobal.contentSecurityManager;
    if (!csm || !csm.isInitialized()) return;

    wx.chooseImage({
      count: 1,
      sizeType: ['compressed'],
      sourceType: ['album', 'camera'],
      success: async (res) => {
        const filePath = res.tempFilePaths[0];

        // Check file size
        const fileInfo = wx.getFileInfo({ filePath });
        if (fileInfo && fileInfo.size > 1024 * 1024) {
          this._errorMessage = '图片大小不能超过1MB';
          return;
        }

        this._isSubmitting = true;
        this._errorMessage = '审核中...';

        // Check image content
        const result = await csm.checkImageContent(filePath, this._openid);

        this._isSubmitting = false;

        if (result.pass) {
          this._profile.avatarUrl = filePath;
          this._saveProfile();
          this._errorMessage = '';
        } else {
          this._errorMessage = result.errmsg || '图片内容违规，请更换';
        }
      },
      fail: () => {
        // User cancelled or error
      },
    });
  },

  // ============================================================
  // Render Helpers
  // ============================================================

  _renderBackButton(ctx) {
    ctx.fillStyle = '#AAAAAA';
    ctx.font = '14px Arial';
    ctx.textAlign = 'left';
    ctx.textBaseline = 'middle';
    ctx.fillText('← ' + t('common.back'), 15, 25);
  },

  _renderAvatar(ctx) {
    const rect = this._avatarRect;
    const cx = rect.x + rect.w / 2;
    const cy = rect.y + rect.h / 2;
    const r = rect.w / 2;

    // Circle background
    ctx.fillStyle = '#4a90d9';
    ctx.beginPath();
    ctx.arc(cx, cy, r, 0, Math.PI * 2);
    ctx.fill();

    // Camera icon
    ctx.fillStyle = '#FFFFFF';
    ctx.font = '24px Arial';
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
    ctx.fillText('📷', cx, cy);

    // Hint text
    ctx.fillStyle = '#888888';
    ctx.font = '10px Arial';
    ctx.fillText(t('profile.changeAvatar'), cx, rect.y + rect.h + 14);
  },

  _renderField(ctx, rect, label, value, field) {
    const isEditing = this._editingField === field;

    // Label
    ctx.fillStyle = '#CCCCCC';
    ctx.font = '12px Arial';
    ctx.textAlign = 'left';
    ctx.textBaseline = 'bottom';
    ctx.fillText(label, rect.x, rect.y - 4);

    // Input box
    ctx.fillStyle = isEditing ? 'rgba(74, 144, 226, 0.2)' : 'rgba(255, 255, 255, 0.1)';
    ctx.fillRect(rect.x, rect.y, rect.w, rect.h);

    // Border
    ctx.strokeStyle = isEditing ? '#4a90d9' : '#555555';
    ctx.lineWidth = 1;
    ctx.strokeRect(rect.x, rect.y, rect.w, rect.h);

    // Value
    ctx.fillStyle = value ? '#FFFFFF' : '#666666';
    ctx.font = '13px Arial';
    ctx.textAlign = 'left';
    ctx.textBaseline = 'middle';
    const displayText = value || t('profile.tapToEdit');
    const truncated = displayText.length > 20 ? displayText.substring(0, 20) + '...' : displayText;
    ctx.fillText(truncated, rect.x + 8, rect.y + rect.h / 2);
  },

  _renderDescriptionField(ctx) {
    const rect = this._descriptionRect;
    const isEditing = this._editingField === FIELD.DESCRIPTION;

    // Label
    ctx.fillStyle = '#CCCCCC';
    ctx.font = '12px Arial';
    ctx.textAlign = 'left';
    ctx.textBaseline = 'bottom';
    ctx.fillText(t('profile.description'), rect.x, rect.y - 4);

    // Input box (taller for description)
    ctx.fillStyle = isEditing ? 'rgba(74, 144, 226, 0.2)' : 'rgba(255, 255, 255, 0.1)';
    ctx.fillRect(rect.x, rect.y, rect.w, rect.h);

    ctx.strokeStyle = isEditing ? '#4a90d9' : '#555555';
    ctx.lineWidth = 1;
    ctx.strokeRect(rect.x, rect.y, rect.w, rect.h);

    // Value (multi-line)
    ctx.fillStyle = this._profile.description ? '#FFFFFF' : '#666666';
    ctx.font = '12px Arial';
    ctx.textAlign = 'left';
    ctx.textBaseline = 'top';
    const displayText = this._profile.description || t('profile.tapToEdit');
    const lines = this._wrapText(ctx, displayText, rect.w - 16, 4);
    for (let i = 0; i < lines.length; i++) {
      ctx.fillText(lines[i], rect.x + 8, rect.y + 6 + i * 16);
    }
  },

  _renderEditOverlay(ctx) {
    // Place overlay at TOP of screen, so save/cancel buttons are NOT hidden by keyboard.
    // The keyboard occupies the bottom portion of the screen when shown.
    const overlayY = 0;
    const overlayH = Math.min(SCREEN_HEIGHT * 0.4, 220);
    ctx.fillStyle = 'rgba(0, 0, 0, 0.92)';
    ctx.fillRect(0, overlayY, SCREEN_WIDTH, overlayH);

    // Field label
    const fieldLabels = {
      [FIELD.NICKNAME]: t('profile.nickname'),
      [FIELD.SIGNATURE]: t('profile.signature'),
      [FIELD.DESCRIPTION]: t('profile.description'),
    };
    ctx.fillStyle = '#AAAAAA';
    ctx.font = '12px Arial';
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
    ctx.fillText('编辑 ' + (fieldLabels[this._editingField] || ''), CENTER_X, overlayY + 14);

    // Input text preview area
    const previewBoxY = overlayY + 30;
    const previewBoxH = 50;
    ctx.fillStyle = 'rgba(255, 255, 255, 0.08)';
    ctx.fillRect(20, previewBoxY, SCREEN_WIDTH - 40, previewBoxH);
    ctx.strokeStyle = '#4a90d9';
    ctx.lineWidth = 1;
    ctx.strokeRect(20, previewBoxY, SCREEN_WIDTH - 40, previewBoxH);

    // Current input text
    ctx.fillStyle = '#FFFFFF';
    ctx.font = '15px Arial';
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
    const previewText = this._inputText || '';
    if (previewText) {
      const lines = this._wrapText(ctx, previewText, SCREEN_WIDTH - 60, 2);
      for (let i = 0; i < lines.length; i++) {
        ctx.fillText(lines[i], CENTER_X, previewBoxY + 16 + i * 18);
      }
    } else {
      // Placeholder
      ctx.fillStyle = '#888888';
      ctx.font = '13px Arial';
      ctx.fillText(
        this._originalText ? `当前: ${this._originalText}（在下方键盘输入新内容）` : '请在下方键盘输入',
        CENTER_X,
        previewBoxY + previewBoxH / 2
      );
    }

    // Character count
    let maxLen = 200;
    if (this._editingField === FIELD.NICKNAME) maxLen = NICKNAME_MAX;
    if (this._editingField === FIELD.SIGNATURE) maxLen = SIGNATURE_MAX;
    ctx.fillStyle = '#888888';
    ctx.font = '11px Arial';
    ctx.textAlign = 'right';
    ctx.fillText(`${this._inputText.length}/${maxLen}`, SCREEN_WIDTH - 24, previewBoxY + previewBoxH + 12);

    // Violation warning
    if (this._localViolation && this._errorMessage) {
      ctx.fillStyle = '#FF4444';
      ctx.font = 'bold 12px Arial';
      ctx.textAlign = 'center';
      ctx.fillText('⚠ ' + this._errorMessage, CENTER_X, previewBoxY + previewBoxH + 12);
    }

    // Buttons row at bottom of overlay
    const btnRowY = overlayY + overlayH - BTN_HEIGHT - 12;
    const btnGap = 12;
    const btnW = (SCREEN_WIDTH - 40 - btnGap) / 2;

    // Cancel button (left)
    this._cancelBtnRect = {
      x: 20,
      y: btnRowY,
      w: btnW,
      h: BTN_HEIGHT,
    };

    // Save button (right)
    this._saveBtnRect = {
      x: 20 + btnW + btnGap,
      y: btnRowY,
      w: btnW,
      h: BTN_HEIGHT,
    };

    const btnR = 6;

    // Cancel button render
    ctx.fillStyle = '#3a3a3a';
    this._drawRoundRect(ctx, this._cancelBtnRect.x, this._cancelBtnRect.y, this._cancelBtnRect.w, this._cancelBtnRect.h, btnR);
    ctx.fill();
    ctx.strokeStyle = '#666666';
    ctx.lineWidth = 1;
    this._drawRoundRect(ctx, this._cancelBtnRect.x, this._cancelBtnRect.y, this._cancelBtnRect.w, this._cancelBtnRect.h, btnR);
    ctx.stroke();
    ctx.fillStyle = '#CCCCCC';
    ctx.font = '14px Arial';
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
    ctx.fillText(t('common.cancel') || '取消', this._cancelBtnRect.x + this._cancelBtnRect.w / 2, this._cancelBtnRect.y + this._cancelBtnRect.h / 2);

    // Save button render: always highlighted unless submitting
    const isActive = !this._isSubmitting;
    if (isActive) {
      ctx.shadowColor = '#00CC66';
      ctx.shadowBlur = 16;
      ctx.shadowOffsetX = 0;
      ctx.shadowOffsetY = 0;
      ctx.fillStyle = '#00CC66';
    } else {
      ctx.shadowColor = 'transparent';
      ctx.shadowBlur = 0;
      ctx.fillStyle = '#3a3a3a';
    }
    this._drawRoundRect(ctx, this._saveBtnRect.x, this._saveBtnRect.y, this._saveBtnRect.w, this._saveBtnRect.h, btnR);
    ctx.fill();
    ctx.shadowColor = 'transparent';
    ctx.shadowBlur = 0;

    if (isActive) {
      ctx.strokeStyle = '#33FF99';
      ctx.lineWidth = 2;
    } else {
      ctx.strokeStyle = '#555555';
      ctx.lineWidth = 1;
    }
    this._drawRoundRect(ctx, this._saveBtnRect.x, this._saveBtnRect.y, this._saveBtnRect.w, this._saveBtnRect.h, btnR);
    ctx.stroke();

    ctx.fillStyle = isActive ? '#FFFFFF' : '#666666';
    ctx.font = 'bold 15px Arial';
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
    ctx.fillText(this._isSubmitting ? '审核中...' : t('profile.save'), this._saveBtnRect.x + this._saveBtnRect.w / 2, this._saveBtnRect.y + this._saveBtnRect.h / 2);
  },

  _handleEditOverlayTouch(x, y) {
    // Save button - always allow click, _handleSubmit will validate
    if (this._hitTest(x, y, this._saveBtnRect)) {
      if (!this._isSubmitting) {
        // Re-validate before submit (in case keyboard callbacks did not fire)
        this._validateInput(this._editingField);
        if (!this._localViolation) {
          this._handleSubmit();
        }
        // If validation fails, error message is now shown via _localViolation/_errorMessage
      }
      return;
    }

    // Cancel button
    if (this._hitTest(x, y, this._cancelBtnRect)) {
      this._stopEditing();
      return;
    }

    // Ignore taps elsewhere inside the overlay (do NOT auto-cancel)
  },

  // ============================================================
  // Utility
  // ============================================================

  _hitTest(x, y, rect) {
    return rect && x >= rect.x && x <= rect.x + rect.w && y >= rect.y && y <= rect.y + rect.h;
  },

  _drawRoundRect(ctx, x, y, w, h, r) {
    ctx.beginPath();
    ctx.moveTo(x + r, y);
    ctx.lineTo(x + w - r, y);
    ctx.arcTo(x + w, y, x + w, y + r, r);
    ctx.lineTo(x + w, y + h - r);
    ctx.arcTo(x + w, y + h, x + w - r, y + h, r);
    ctx.lineTo(x + r, y + h);
    ctx.arcTo(x, y + h, x, y + h - r, r);
    ctx.lineTo(x, y + r);
    ctx.arcTo(x, y, x + r, y, r);
    ctx.closePath();
  },

  _wrapText(ctx, text, maxWidth, maxLines) {
    const words = text.split('');
    const lines = [];
    let currentLine = '';

    for (const char of words) {
      const testLine = currentLine + char;
      const metrics = ctx.measureText(testLine);
      if (metrics.width > maxWidth && currentLine.length > 0) {
        lines.push(currentLine);
        currentLine = char;
        if (lines.length >= maxLines) {
          lines[lines.length - 1] += '...';
          break;
        }
      } else {
        currentLine = testLine;
      }
    }
    if (currentLine && lines.length < maxLines) {
      lines.push(currentLine);
    }

    return lines;
  },

  _loadProfile() {
    try {
      const saved = wx.getStorageSync('player_profile');
      if (saved) {
        this._profile = { ...this._profile, ...JSON.parse(saved) };
      }
    } catch (e) {
      console.warn('[ProfileScene] Failed to load profile:', e);
    }
  },

  _saveProfile() {
    try {
      wx.setStorageSync('player_profile', JSON.stringify(this._profile));
    } catch (e) {
      console.warn('[ProfileScene] Failed to save profile:', e);
    }
  },
};

module.exports = ProfileScene;