import { BadRequestException, Body, Controller, Delete, Get, Logger, Param, ParseIntPipe, Post, Put, Query, UseGuards } from '@nestjs/common';
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
import { RequirePermission } from '../auth/decorators/permission.decorator';
import { SyncService } from './sync.service';
import type { SyncPlatform } from '../entities/sync-log.entity';
import { ScheduleSyncQueryDto } from './dto/schedule-sync.dto';

@UseGuards(JwtAuthGuard)
@Controller('sync')
export class SyncController {
  private readonly logger = new Logger(SyncController.name);
  constructor(private readonly syncService: SyncService) {}

  @Post('trigger')
  @RequirePermission('sync:trigger')
  async triggerSync(
    @Query('platform') platform?: SyncPlatform,
    @Query('rootDeptId') rootDeptId?: string,
  ) {
    const rootId = rootDeptId ? this.parseRootDeptId(rootDeptId) : 1;
    const logs = await this.syncService.triggerSync(platform, rootId);
    return { synced: logs.length, logs };
  }

  @Get('status')
  @RequirePermission('sync:read')
  async getStatus() {
    const lastDingTalkStudents = await this.syncService.getLastSync('dingtalk_students');
    const lastDingTalkAttendance = await this.syncService.getLastSync('dingtalk_attendance');
    const lastWeCom = await this.syncService.getLastSync('wecom');
    return {
      dingTalkStudents: lastDingTalkStudents ? { lastSyncAt: lastDingTalkStudents.finishedAt, status: lastDingTalkStudents.status } : null,
      dingTalkAttendance: lastDingTalkAttendance ? { lastSyncAt: lastDingTalkAttendance.finishedAt, status: lastDingTalkAttendance.status } : null,
      weCom: lastWeCom ? { lastSyncAt: lastWeCom.finishedAt, status: lastWeCom.status } : null,
    };
  }

  /** 获取钉钉组织部门树，供前端选择同步起点 */
  @Get('dingtalk/org-tree')
  @RequirePermission('sync:read')
  async getDingTalkOrgTree(@Query('rootDeptId') rootDeptId?: string) {
    const rootId = rootDeptId ? this.parseRootDeptId(rootDeptId) : 1;
    const tree = await this.syncService.getDingTalkOrgTree(rootId);
    return { success: true, data: tree };
  }

  /** 获取钉钉组织部门树（含用户），供同步用户选择器使用 */
  @Get('dingtalk/org-tree-with-users')
  @RequirePermission('sync:read')
  async getDingTalkOrgTreeWithUsers(@Query('rootDeptId') rootDeptId?: string) {
    const rootId = rootDeptId ? this.parseRootDeptId(rootDeptId) : 1;
    const tree = await this.syncService.getDingTalkOrgTreeWithUsers(rootId);
    return { success: true, data: tree };
  }

  @Get('dingtalk/attendance-groups')
  @RequirePermission('sync:read')
  async getDingTalkAttendanceGroups() {
    return { success: true, data: await this.syncService.getDingTalkAttendanceGroups() };
  }

  @Post('dingtalk/attendance-groups/delete-all')
  @RequirePermission('sync:trigger')
  async deleteAllDingTalkAttendanceGroups() {
    return {
      success: true,
      data: await this.syncService.deleteAllDingTalkAttendanceGroups(),
    };
  }

  /** 从金数据表单同步学生数据 */
  @Post('jinshuju')
  @RequirePermission('sync:trigger')
  async syncJinshuju(
    @Body() body: { apiKey: string; apiSecret: string; formToken: string },
  ) {
    if (!body.apiKey || !body.apiSecret || !body.formToken) {
      throw new BadRequestException('apiKey, apiSecret, formToken 均为必填');
    }
    const log = await this.syncService.syncJinshuju(body.apiKey, body.apiSecret, body.formToken);
    return { success: true, log };
  }

  /** 获取金数据表单字段，供匹配规则选择器使用 */
  @Post('jinshuju/fields')
  @RequirePermission('sync:trigger')
  async getJinshujuFields(
    @Body() body: { apiKey: string; apiSecret: string; formToken: string },
  ) {
    if (!body.apiKey || !body.apiSecret || !body.formToken) {
      throw new BadRequestException('apiKey, apiSecret, formToken 均为必填');
    }
    const data = await this.syncService.getJinshujuFormFields(
      body.apiKey,
      body.apiSecret,
      body.formToken,
    );
    return { success: true, data };
  }

  /** 预览金数据表单条目及建议匹配（不写入） */
  @Post('jinshuju/preview')
  @RequirePermission('sync:trigger')
  async previewJinshuju(
    @Body() body: { apiKey: string; apiSecret: string; formToken: string; ruleId?: number },
  ) {
    if (!body.apiKey || !body.apiSecret || !body.formToken) {
      throw new BadRequestException('apiKey, apiSecret, formToken 均为必填');
    }
    const data = await this.syncService.previewJinshuju(body.apiKey, body.apiSecret, body.formToken, body.ruleId);
    return { success: true, ...data };
  }

  /** 应用用户的手动匹配决定 */
  @Post('jinshuju/apply')
  @RequirePermission('sync:trigger')
  async applyJinshuju(
    @Body() body: {
      apiKey: string;
      apiSecret: string;
      formToken: string;
      ruleId?: number;
      decisions: Array<{
        serialNumber: number;
        action: 'match' | 'create' | 'skip';
        matchStudentId?: number;
        createName?: string;
        createPhone?: string;
      }>;
    },
  ) {
    if (!body.apiKey || !body.apiSecret || !body.formToken) {
      throw new BadRequestException('apiKey, apiSecret, formToken 均为必填');
    }
    if (!Array.isArray(body.decisions) || body.decisions.length === 0) {
      throw new BadRequestException('decisions 不能为空');
    }
    const log = await this.syncService.applyJinshuju(
      body.apiKey,
      body.apiSecret,
      body.formToken,
      body.decisions,
      body.ruleId,
    );
    return { success: true, log };
  }

  // ── 金数据匹配规则 CRUD ──

  @Get('jinshuju/rules')
  @RequirePermission('sync:read')
  async listMatchRules() {
    const rules = await this.syncService.listMatchRules();
    return { success: true, data: rules };
  }

  @Post('jinshuju/rules')
  @RequirePermission('sync:trigger')
  async createMatchRule(
    @Body() body: { name: string; formToken: string; mappings: Record<string, string> },
  ) {
    if (!body.name || !body.formToken) {
      throw new BadRequestException('name, formToken 均为必填');
    }
    const rule = await this.syncService.createMatchRule({
      name: body.name,
      formToken: body.formToken,
      mappings: body.mappings ?? {},
    });
    return { success: true, data: rule };
  }

  @Put('jinshuju/rules/:id')
  @RequirePermission('sync:trigger')
  async updateMatchRule(
    @Param('id', ParseIntPipe) id: number,
    @Body() body: { name?: string; mappings?: Record<string, string> },
  ) {
    const rule = await this.syncService.updateMatchRule(id, body);
    return { success: true, data: rule };
  }

  @Delete('jinshuju/rules/:id')
  @RequirePermission('sync:trigger')
  async deleteMatchRule(@Param('id', ParseIntPipe) id: number) {
    await this.syncService.deleteMatchRule(id);
    return { success: true };
  }

  @Get('logs')
  @RequirePermission('sync:read')
  async getLogs(
    @Query('platform') platform?: SyncPlatform,
    @Query('limit') limit?: number,
  ) {
    return this.syncService.getLogs(platform, limit ? Number(limit) : 50);
  }

  // ── 排班同步 ──

  /** 触发排班同步到钉钉考勤排班 */
  @Post('schedule/sync')
  @RequirePermission('sync:trigger')
  async syncSchedule(@Query() query: ScheduleSyncQueryDto) {
    const result = await this.syncService.syncScheduleToDingTalk(
      query.dateFrom,
      query.days,
      query.attendanceMachineOnly,
    );
    return { success: true, data: result };
  }

  /** 查询钉钉排班状态（核对本地 vs 钉钉） */
  @Get('schedule/status')
  @RequirePermission('sync:read')
  async getScheduleStatus(
    @Query('date') date?: string,
  ) {
    const status = await this.syncService.getScheduleSyncStatus(date);
    return { success: true, data: status };
  }


  private parseRootDeptId(rootDeptId: string): number {
    if (!/^\d+$/.test(rootDeptId)) {
      throw new BadRequestException('rootDeptId must be a positive integer');
    }
    const parsed = Number(rootDeptId);
    if (!Number.isSafeInteger(parsed) || parsed < 1) {
      throw new BadRequestException('rootDeptId must be a positive integer');
    }
    return parsed;
  }
}
