import { Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';

export const PLAYER_ALLOW_PASSWORD_CHANGE = 'player.allow_password_change';
export const PLAYER_ALLOW_USERNAME_CHANGE = 'player.allow_username_change';
export const AGENT_SUSPEND_FREEZE_DIRECT_PLAYERS = 'agent.suspend_freeze_direct_players';
export const AGENT_SUSPEND_BLOCK_PLAYER_LOGIN = 'agent.suspend_block_player_login';
export const AGENT_MAX_LEVEL = 'agent.max_level';
export const AGENT_DEFAULT_SUB_CREDIT_RATIO = 'agent.default_sub_credit_ratio';
export const CASHBACK_PLATFORM_DIRECT_RATE = 'cashback.platform_direct_rate';
export const CASHBACK_ADMIN_INVITE_RATE = 'cashback.admin_invite_rate';
export const INBOX_NOTIFY_DEPOSIT = 'inbox.notify.deposit';
export const INBOX_FEATURE_ENABLED = 'inbox.feature_enabled';
export const INBOX_NOTIFY_BANNER = 'inbox.notify.banner';
export const INBOX_NOTIFY_ANNOUNCEMENT = 'inbox.notify.announcement';

export type InboxNotifySettings = {
  /** 玩家端是否展示站内邮箱（关闭后入口直达客服） */
  inboxEnabled: boolean;
  /** 充值审核通过/拒绝时发送站内信 */
  deposit: boolean;
  /** 发布 Banner 内容时发送站内信推广 */
  banner: boolean;
  /** 发布公告/滚动条内容时发送站内信推广 */
  announcement: boolean;
};

export type PlatformDirectCashbackSettings = {
  /** 平台直属玩家默认返水比例（小数，0.01 = 1%） */
  platformDirectRate: number;
  /** 管理员邀请注册玩家返水比例；未配置时与 platformDirectRate 相同 */
  adminInviteRate: number;
};

export type AgentHierarchySettings = {
  /** 最大代理层级；0 = 不限制 */
  maxAgentLevel: number;
  /** 创建下级代理时默认授信占上级可用授信的比例（1–100） */
  defaultSubAgentCreditRatio: number;
};

export type PlayerAccountSettings = {
  allowPasswordChange: boolean;
  allowUsernameChange: boolean;
};

export type AgentSuspendSettings = {
  /** 停用代理时默认级联冻结直属玩家（单次操作仍可覆盖） */
  suspendFreezeDirectPlayers: boolean;
  /** 停用代理时默认禁止直属玩家登录（单次操作仍可覆盖） */
  suspendBlockPlayerLogin: boolean;
};

@Injectable()
export class SystemConfigService {
  constructor(private prisma: PrismaService) {}

  async getBoolean(key: string, defaultValue: boolean): Promise<boolean> {
    const row = await this.prisma.systemConfig.findUnique({ where: { configKey: key } });
    if (!row) return defaultValue;
    return row.configValue === 'true' || row.configValue === '1';
  }

  async setBoolean(key: string, value: boolean, description?: string) {
    await this.prisma.systemConfig.upsert({
      where: { configKey: key },
      create: {
        configKey: key,
        configValue: value ? 'true' : 'false',
        description,
      },
      update: { configValue: value ? 'true' : 'false' },
    });
  }

  async getInt(key: string, defaultValue: number): Promise<number> {
    const row = await this.prisma.systemConfig.findUnique({ where: { configKey: key } });
    if (!row) return defaultValue;
    const parsed = parseInt(row.configValue, 10);
    return Number.isFinite(parsed) ? parsed : defaultValue;
  }

  async setInt(key: string, value: number, description?: string) {
    await this.prisma.systemConfig.upsert({
      where: { configKey: key },
      create: {
        configKey: key,
        configValue: String(value),
        description,
      },
      update: { configValue: String(value) },
    });
  }

  async getPlayerAccountSettings(): Promise<PlayerAccountSettings> {
    const [allowPasswordChange, allowUsernameChange] = await Promise.all([
      this.getBoolean(PLAYER_ALLOW_PASSWORD_CHANGE, true),
      this.getBoolean(PLAYER_ALLOW_USERNAME_CHANGE, false),
    ]);
    return { allowPasswordChange, allowUsernameChange };
  }

  async updatePlayerAccountSettings(data: Partial<PlayerAccountSettings>) {
    if (data.allowPasswordChange !== undefined) {
      await this.setBoolean(
        PLAYER_ALLOW_PASSWORD_CHANGE,
        data.allowPasswordChange,
        '玩家是否可在客户端修改密码',
      );
    }
    if (data.allowUsernameChange !== undefined) {
      await this.setBoolean(
        PLAYER_ALLOW_USERNAME_CHANGE,
        data.allowUsernameChange,
        '玩家是否可在客户端修改登录账号名',
      );
    }
    return this.getPlayerAccountSettings();
  }

  async getAgentSuspendSettings(): Promise<AgentSuspendSettings> {
    const [suspendFreezeDirectPlayers, suspendBlockPlayerLogin] = await Promise.all([
      this.getBoolean(AGENT_SUSPEND_FREEZE_DIRECT_PLAYERS, false),
      this.getBoolean(AGENT_SUSPEND_BLOCK_PLAYER_LOGIN, false),
    ]);
    return { suspendFreezeDirectPlayers, suspendBlockPlayerLogin };
  }

  async updateAgentSuspendSettings(data: Partial<AgentSuspendSettings>) {
    if (data.suspendFreezeDirectPlayers !== undefined) {
      await this.setBoolean(
        AGENT_SUSPEND_FREEZE_DIRECT_PLAYERS,
        data.suspendFreezeDirectPlayers,
        '停用代理时是否允许级联冻结直属玩家',
      );
    }
    if (data.suspendBlockPlayerLogin !== undefined) {
      await this.setBoolean(
        AGENT_SUSPEND_BLOCK_PLAYER_LOGIN,
        data.suspendBlockPlayerLogin,
        '上级代理停用时是否禁止直属玩家登录',
      );
    }
    return this.getAgentSuspendSettings();
  }

  async getAgentHierarchySettings(): Promise<AgentHierarchySettings> {
    const [maxAgentLevel, defaultSubAgentCreditRatio] = await Promise.all([
      this.getInt(AGENT_MAX_LEVEL, 0),
      this.getInt(AGENT_DEFAULT_SUB_CREDIT_RATIO, 50),
    ]);
    return { maxAgentLevel, defaultSubAgentCreditRatio };
  }

  async updateAgentHierarchySettings(data: Partial<AgentHierarchySettings>) {
    if (data.maxAgentLevel !== undefined) {
      if (!Number.isInteger(data.maxAgentLevel) || data.maxAgentLevel < 0) {
        throw new Error('maxAgentLevel must be a non-negative integer');
      }
      await this.setInt(
        AGENT_MAX_LEVEL,
        data.maxAgentLevel,
        '最大代理层级；0 表示不限制',
      );
    }
    if (data.defaultSubAgentCreditRatio !== undefined) {
      if (
        !Number.isInteger(data.defaultSubAgentCreditRatio) ||
        data.defaultSubAgentCreditRatio < 1 ||
        data.defaultSubAgentCreditRatio > 100
      ) {
        throw new Error('defaultSubAgentCreditRatio must be an integer between 1 and 100');
      }
      await this.setInt(
        AGENT_DEFAULT_SUB_CREDIT_RATIO,
        data.defaultSubAgentCreditRatio,
        '创建下级代理时默认授信占上级可用授信的比例（%）',
      );
    }
    return this.getAgentHierarchySettings();
  }

  async getDecimalRate(key: string, defaultValue = 0): Promise<number> {
    const row = await this.prisma.systemConfig.findUnique({ where: { configKey: key } });
    if (!row) return defaultValue;
    const parsed = parseFloat(row.configValue);
    return Number.isFinite(parsed) && parsed >= 0 ? parsed : defaultValue;
  }

  async setDecimalRate(key: string, value: number, description?: string) {
    const safe = Math.max(0, value);
    await this.prisma.systemConfig.upsert({
      where: { configKey: key },
      create: {
        configKey: key,
        configValue: String(safe),
        description,
      },
      update: { configValue: String(safe) },
    });
  }

  async getPlatformDirectCashbackSettings(): Promise<PlatformDirectCashbackSettings> {
    const platformDirectRate = await this.getDecimalRate(CASHBACK_PLATFORM_DIRECT_RATE, 0);
    const adminInviteConfigured = await this.prisma.systemConfig.findUnique({
      where: { configKey: CASHBACK_ADMIN_INVITE_RATE },
    });
    const adminInviteRate = adminInviteConfigured
      ? await this.getDecimalRate(CASHBACK_ADMIN_INVITE_RATE, platformDirectRate)
      : platformDirectRate;
    return { platformDirectRate, adminInviteRate };
  }

  async updatePlatformDirectCashbackSettings(data: {
    platformDirectRate?: number;
    adminInviteRate?: number;
  }) {
    if (data.platformDirectRate !== undefined) {
      if (!Number.isFinite(data.platformDirectRate) || data.platformDirectRate < 0) {
        throw new Error('platformDirectRate must be a non-negative number');
      }
      await this.setDecimalRate(
        CASHBACK_PLATFORM_DIRECT_RATE,
        data.platformDirectRate,
        '平台直属玩家默认返水比例（小数，如 0.01 = 1%）',
      );
    }
    if (data.adminInviteRate !== undefined) {
      if (!Number.isFinite(data.adminInviteRate) || data.adminInviteRate < 0) {
        throw new Error('adminInviteRate must be a non-negative number');
      }
      await this.setDecimalRate(
        CASHBACK_ADMIN_INVITE_RATE,
        data.adminInviteRate,
        '管理员邀请注册玩家返水比例（小数，如 0.01 = 1%）',
      );
    }
    return this.getPlatformDirectCashbackSettings();
  }

  async getInboxFeatureEnabled(): Promise<boolean> {
    return this.getBoolean(INBOX_FEATURE_ENABLED, true);
  }

  async getInboxNotifySettings(): Promise<InboxNotifySettings> {
    const [inboxEnabled, deposit, banner, announcement] = await Promise.all([
      this.getBoolean(INBOX_FEATURE_ENABLED, true),
      this.getBoolean(INBOX_NOTIFY_DEPOSIT, true),
      this.getBoolean(INBOX_NOTIFY_BANNER, true),
      this.getBoolean(INBOX_NOTIFY_ANNOUNCEMENT, true),
    ]);
    return { inboxEnabled, deposit, banner, announcement };
  }

  async updateInboxNotifySettings(data: Partial<InboxNotifySettings>) {
    if (data.inboxEnabled !== undefined) {
      await this.setBoolean(
        INBOX_FEATURE_ENABLED,
        data.inboxEnabled,
        '玩家端是否开启站内邮箱功能',
      );
    }
    if (data.deposit !== undefined) {
      await this.setBoolean(
        INBOX_NOTIFY_DEPOSIT,
        data.deposit,
        '充值审核结果是否通过站内邮箱通知玩家',
      );
    }
    if (data.banner !== undefined) {
      await this.setBoolean(
        INBOX_NOTIFY_BANNER,
        data.banner,
        '发布 Banner 内容时是否发送站内信推广',
      );
    }
    if (data.announcement !== undefined) {
      await this.setBoolean(
        INBOX_NOTIFY_ANNOUNCEMENT,
        data.announcement,
        '发布公告/滚动条内容时是否发送站内信推广',
      );
    }
    return this.getInboxNotifySettings();
  }

  async getDepositScreenshotCleanupConfig(): Promise<{ enabled: boolean; keepDays: number }> {
    const enabled = await this.getBoolean('deposit.cleanup.enabled', false);
    const keepDays = await this.getInt('deposit.cleanup.keep_days', 180);
    return { enabled, keepDays };
  }

  async updateDepositScreenshotCleanupConfig(data: { enabled?: boolean; keepDays?: number }) {
    if (data.enabled !== undefined) {
      await this.setBoolean(
        'deposit.cleanup.enabled',
        data.enabled,
        '是否开启定时清理充值截图',
      );
    }
    if (data.keepDays !== undefined) {
      if (!Number.isInteger(data.keepDays) || data.keepDays <= 0) {
        throw new Error('keepDays must be a positive integer');
      }
      await this.setInt(
        'deposit.cleanup.keep_days',
        data.keepDays,
        '充值截图保留天数',
      );
    }
    return this.getDepositScreenshotCleanupConfig();
  }
}
