import {
  Injectable,
  NotFoundException,
  BadRequestException,
} from '@nestjs/common';
import { PrismaService } from '@shared/prisma/prisma.service';
import { Create{{pascalName}}Dto } from '../dto/create-{{kebabName}}.dto';
import { Update{{pascalName}}Dto } from '../dto/update-{{kebabName}}.dto';
import { Query{{pascalName}}Dto } from '../dto/query-{{kebabName}}.dto';
import { Prisma } from '@prisma/client';
import { PrismaClientKnownRequestError } from '@prisma/client/runtime/library';

@Injectable()
export class {{pascalName}}Service {
  constructor(private readonly prisma: PrismaService) {}

  async create(create{{pascalName}}Dto: Create{{pascalName}}Dto) {
    try {
      const {{camelName}} = await this.prisma.{{camelName}}.create({
        data: create{{pascalName}}Dto,
        include: this.getIncludeOptions(),
      });

      return {{camelName}};
    } catch (error) {
      if (error instanceof PrismaClientKnownRequestError) {
        if (error.code === 'P2002') {
          throw new BadRequestException('{{name}}已存在');
        }
        if (error.code === 'P2003') {
          throw new BadRequestException('关联的资源不存在');
        }
      }
      throw error;
    }
  }

  async findAll(query: Query{{pascalName}}Dto) {
    const { page = 1, pageSize = 10, sortBy = 'createdAt', sortOrder = 'desc', ...filters } = query;

    const skip = (page - 1) * pageSize;
    const take = pageSize;

    const where = this.buildWhereClause(filters);
    const orderBy = { [sortBy]: sortOrder };

    const [data, total] = await Promise.all([
      this.prisma.{{camelName}}.findMany({
        where,
        orderBy,
        skip,
        take,
        include: this.getIncludeOptions(),
      }),
      this.prisma.{{camelName}}.count({ where }),
    ]);

    return {
      data,
      total,
      page,
      pageSize,
      totalPages: Math.ceil(total / pageSize),
    };
  }

  async findOne({{#if hasCompositeId}}{{#each compositeIdFields}}{{this}}: string{{#unless @last}}, {{/unless}}{{/each}}{{else}}id: string{{/if}}) {
    const {{camelName}} = await this.prisma.{{camelName}}.findUnique({
      where: { {{#if hasCompositeId}}{{compositeIdWhere compositeIdFields}}{{else}}id{{/if}} },
      include: this.getIncludeOptions(),
    });

    if (!{{camelName}}) {
      throw new NotFoundException(`{{name}}{{#if hasCompositeId}}{{#each compositeIdFields}} {{this}}: ${ {{this}} }{{#unless @last}},{{/unless}}{{/each}}{{else}} ID: ${id}{{/if}} 不存在`);
    }

    return {{camelName}};
  }

  {{#each uniqueFields}}
  {{#unless isComposite}}
  async findBy{{pascalCase name}}({{fields.[0]}}: string) {
    const {{../camelName}} = await this.prisma.{{../camelName}}.findUnique({
      where: { {{fields.[0]}} },
      include: this.getIncludeOptions(),
    });

    if (!{{../camelName}}) {
      throw new NotFoundException(`{{../name}} with {{fields.[0]}}: ${{{fields.[0]}}} 不存在`);
    }

    return {{../camelName}};
  }

  {{/unless}}
  {{/each}}

  {{#each uniqueFields}}
  {{#if isComposite}}
  async findBy{{pascalCase name}}({{#each fields}}{{this}}: string{{#unless @last}}, {{/unless}}{{/each}}) {
    const {{../camelName}} = await this.prisma.{{../camelName}}.findUnique({
      where: {
        {{name}}: {
          {{#each fields}}
          {{this}}: {{this}},
          {{/each}}
        }
      },
      include: this.getIncludeOptions(),
    });

    if (!{{../camelName}}) {
      throw new NotFoundException(`{{../name}} with {{#each fields}}{{this}}: ${{{this}}{{#unless @last}}, {{/unless}}{{/each}} 不存在`);
    }

    return {{../camelName}};
  }

  {{/if}}
  {{/each}}

  {{#each indexes}}
  async findBy{{pascalCase name}}({{#each fields}}{{this}}: string{{#unless @last}}, {{/unless}}{{/each}}) {
    const {{../camelName}}s = await this.prisma.{{../camelName}}.findMany({
      where: {
        {{#if isComposite}}
        AND: [
          {{#each fields}}
          { {{this}}: {{this}} },
          {{/each}}
        ]
        {{else}}
        {{#each fields}}{{this}}: {{this}}{{/each}}
        {{/if}}
      },
      include: this.getIncludeOptions(),
    });

    return {{../camelName}}s;
  }

  {{/each}}

  async update({{#if hasCompositeId}}{{#each compositeIdFields}}{{this}}: string, {{/each}}{{else}}id: string, {{/if}}update{{pascalName}}Dto: Update{{pascalName}}Dto) {
    try {
      const {{camelName}} = await this.prisma.{{camelName}}.update({
        where: { {{#if hasCompositeId}}{{compositeIdWhere compositeIdFields}}{{else}}id{{/if}} },
        data: update{{pascalName}}Dto,
        include: this.getIncludeOptions(),
      });

      return {{camelName}};
    } catch (error) {
      if (error instanceof PrismaClientKnownRequestError) {
        if (error.code === 'P2025') {
          throw new NotFoundException(`{{name}}{{#if hasCompositeId}}{{#each compositeIdFields}} {{this}}: ${ {{this}} }{{#unless @last}},{{/unless}}{{/each}}{{else}} ID: ${id}{{/if}} 不存在`);
        }
        if (error.code === 'P2002') {
          throw new BadRequestException('{{name}}已存在');
        }
        if (error.code === 'P2003') {
          throw new BadRequestException('关联的资源不存在');
        }
      }
      throw error;
    }
  }

  async remove({{#if hasCompositeId}}{{#each compositeIdFields}}{{this}}: string{{#unless @last}}, {{/unless}}{{/each}}{{else}}id: string{{/if}}) {
    try {
      await this.prisma.{{camelName}}.delete({
        where: { {{#if hasCompositeId}}{{compositeIdWhere compositeIdFields}}{{else}}id{{/if}} },
      });
    } catch (error) {
      if (error instanceof PrismaClientKnownRequestError) {
        if (error.code === 'P2025') {
          throw new NotFoundException(`{{name}}{{#if hasCompositeId}}{{#each compositeIdFields}} {{this}}: ${ {{this}} }{{#unless @last}},{{/unless}}{{/each}}{{else}} ID: ${id}{{/if}} 不存在`);
        }
        if (error.code === 'P2003') {
          throw new BadRequestException('无法删除，存在关联的资源');
        }
      }
      throw error;
    }
  }

  // 批量操作
  async createMany(data: Create{{pascalName}}Dto[]) {
    return await this.prisma.{{camelName}}.createMany({
      data,
      skipDuplicates: true,
    });
  }

  async updateMany(ids: string[], data: Update{{pascalName}}Dto) {
    return await this.prisma.{{camelName}}.updateMany({
      where: { id: { in: ids } },
      data,
    });
  }

  async removeMany(ids: string[]) {
    return await this.prisma.{{camelName}}.deleteMany({
      where: { id: { in: ids } },
    });
  }

  // 构建查询条件
  private buildWhereClause(filters: any): Prisma.{{pascalName}}WhereInput {
    const where: any = {};

    {{#each fields}}
    {{#if (isQueryField this)}}
    if (filters.{{name}} !== undefined) {
      {{#if (eq type 'string')}}
      where.{{name}} = {
        contains: filters.{{name}},
        mode: 'insensitive',
      };
      {{else}}
      where.{{name}} = filters.{{name}};
      {{/if}}
    }
    {{/if}}
    {{/each}}

    return where;
  }

  // 获取关联数据选项
  private getIncludeOptions() {
    return {
      {{#each relations}}
      {{name}}: true,
      {{/each}}
    };
  }

  // 事务示例
  async createWithRelations(data: any) {
    return await this.prisma.$transaction(async (tx) => {
      // 在事务中执行多个操作
      const {{camelName}} = await tx.{{camelName}}.create({
        data: data.{{camelName}},
        include: this.getIncludeOptions(),
      });

      // 创建关联数据
      // await tx.relatedModel.create({ ... });

      return {{camelName}};
    });
  }
}