import {
  BadRequestException,
  ConflictException,
  Injectable,
} from '@nestjs/common';
import { PrismaService } from 'nestjs-prisma';
import {
  CreateCanvasDto,
  CreateSavedQueryDto,
  PublishCanvasDto,
  UpdateCanvasDto,
} from './canvas.dto';

const SAVED_QUERY_FORBIDDEN =
  /\b(INSERT|UPDATE|DELETE|DROP|ALTER|TRUNCATE|CREATE|REPLACE|MERGE)\b/i;

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

  findAllByUser(userId: string) {
    return this.prisma.canvas.findMany({
      where: { userId },
      orderBy: { createdAt: 'asc' },
    });
  }

  findOne(id: string, userId: string) {
    return this.prisma.canvas.findFirst({
      where: { id, userId },
    });
  }

  async findByPageCode(slug: string) {
    const canvas = await this.prisma.canvas.findFirst({
      where: { publishedPageCode: slug },
    });
    if (!canvas) {
      throw new BadRequestException(`No published canvas for code: ${slug}`);
    }
    return { items: canvas.items, layout: canvas.layout, name: canvas.name };
  }

  async create(userId: string, dto: CreateCanvasDto) {
    const existing = await this.prisma.canvas.findFirst({
      where: { userId, name: dto.name },
    });
    if (existing) {
      throw new ConflictException('Canvas 名称已存在');
    }
    return this.prisma.canvas.create({
      data: {
        userId,
        name: dto.name,
        items: dto.items ?? [],
        layout: dto.layout ?? [],
      },
    });
  }

  async update(id: string, userId: string, dto: UpdateCanvasDto) {
    if (dto.name !== undefined) {
      const existing = await this.prisma.canvas.findFirst({
        where: { userId, name: dto.name, NOT: { id } },
      });
      if (existing) {
        throw new ConflictException('Canvas 名称已存在');
      }
    }

    // 如果改名且已发布，同步更新 page 表的所有名称字段 + code + path
    if (dto.name !== undefined) {
      const canvas = await this.prisma.canvas.findFirst({
        where: { id, userId },
      });
      if (canvas?.publishedPageCode) {
        const newSlug =
          dto.name
            .toLowerCase()
            .replace(/[\s_]+/g, '-')
            .replace(/[^a-z0-9一-鿿-]/g, '')
            .replace(/^-+|-+$/g, '') || 'canvas-page';

        await this.prisma.page.updateMany({
          where: { code: canvas.publishedPageCode },
          data: {
            code: newSlug,
            name: dto.name,
            zhName: dto.name,
            path: `/admin/p/${newSlug}`,
          },
        });

        // 同步更新 canvas 的 publishedPageCode 指向新 code
        await this.prisma.canvas.update({
          where: { id },
          data: { publishedPageCode: newSlug },
        });
      }
    }

    return this.prisma.canvas.updateMany({
      where: { id, userId },
      data: {
        ...(dto.name !== undefined && { name: dto.name }),
        ...(dto.items !== undefined && { items: dto.items }),
        ...(dto.layout !== undefined && { layout: dto.layout }),
        ...(dto.publishedPageCode !== undefined && {
          publishedPageCode: dto.publishedPageCode,
        }),
      },
    });
  }

  async remove(id: string, userId: string) {
    const canvas = await this.prisma.canvas.findFirst({
      where: { id, userId },
    });
    if (!canvas) {
      throw new BadRequestException('Canvas not found');
    }

    // If published, delete the page record
    if (canvas.publishedPageCode) {
      const page = await this.prisma.page.findFirst({
        where: { code: canvas.publishedPageCode },
      });
      if (page) {
        await this.prisma.rolePages.deleteMany({ where: { pageId: page.id } });
        await this.prisma.page.delete({ where: { id: page.id } });
      }
    }

    // Delete publish history
    await this.prisma.canvasPublish.deleteMany({ where: { canvasId: id } });

    // Delete canvas
    return this.prisma.canvas.delete({ where: { id } });
  }

  async publish(id: string, userId: string, dto: PublishCanvasDto) {
    const canvas = await this.prisma.canvas.findFirst({
      where: { id, userId },
    });
    if (!canvas) {
      throw new BadRequestException('Canvas not found');
    }

    // 确定 parentId
    const parent = dto.parentPageCode
      ? await this.prisma.page.findUnique({
          where: { code: dto.parentPageCode },
        })
      : null;
    const parentId = parent?.id ?? null;

    // 算 sortOrder（插在同级末尾）
    const siblings = await this.prisma.page.findMany({
      where: { parentId },
      orderBy: { sortOrder: 'desc' },
      take: 1,
    });
    const nextSort = (siblings[0]?.sortOrder ?? 1000) + 10;

    // upsert page 记录（导航栏）
    const page = await this.prisma.page.upsert({
      where: { code: dto.slug },
      update: { zhName: dto.pageName, name: dto.pageName },
      create: {
        code: dto.slug,
        name: dto.pageName,
        zhName: dto.pageName,
        enName: dto.slug,
        path: `/admin/p/${dto.slug}`,
        isVirtual: false,
        sortOrder: nextSort,
        parentId,
      },
    });

    // 给 SYSTEM_ADMIN 授权
    const role = await this.prisma.role.findFirst({
      where: { name: 'SYSTEM_ADMIN' },
    });
    if (role) {
      await this.prisma.rolePages.upsert({
        where: { roleId_pageId: { roleId: role.id, pageId: page.id } },
        update: {},
        create: { roleId: role.id, pageId: page.id },
      });
    }

    // 更新 canvas 的 publishedPageCode
    await this.prisma.canvas.update({
      where: { id },
      data: { publishedPageCode: dto.slug, publishedAt: new Date() },
    });

    return { success: true, pageCode: dto.slug };
  }

  async unpublish(id: string, userId: string) {
    const canvas = await this.prisma.canvas.findFirst({
      where: { id, userId },
    });
    if (!canvas) {
      throw new BadRequestException('Canvas not found');
    }
    if (!canvas.publishedPageCode) {
      throw new BadRequestException('Canvas is not published');
    }

    // 删除 page 记录和权限
    const page = await this.prisma.page.findFirst({
      where: { code: canvas.publishedPageCode },
    });
    if (page) {
      await this.prisma.rolePages.deleteMany({ where: { pageId: page.id } });
      await this.prisma.page.delete({ where: { id: page.id } });
    }

    // 清空发布状态
    await this.prisma.canvas.update({
      where: { id },
      data: { publishedPageCode: null, publishedAt: null },
    });

    return { success: true };
  }

  async savedQueryCreate(dto: CreateSavedQueryDto) {
    const sql = dto.sql.trim();
    if (!sql.toUpperCase().startsWith('SELECT')) {
      throw new BadRequestException('Only SELECT statements are allowed');
    }
    if (SAVED_QUERY_FORBIDDEN.test(sql)) {
      throw new BadRequestException('SQL contains forbidden keywords');
    }
    return this.prisma.savedQuery.create({
      data: { sql, description: dto.description },
    });
  }

  async savedQueryRun(id: number) {
    const record = await this.prisma.savedQuery.findUnique({ where: { id } });
    if (!record) throw new BadRequestException(`SavedQuery ${id} not found`);
    return this.prisma.$queryRawUnsafe(record.sql);
  }
}
