/**
 * 表单定义服务
 * 完全符合 API 文档规范
 */

import {
  Injectable,
  Logger,
  NotFoundException,
  BadRequestException,
  ConflictException,
} from '@nestjs/common';
import { PrismaService } from '@core/database/prisma/prisma.service';
import { FormStatus, FormVersionStatus, Prisma } from '@prisma/client';
import {
  CreateFormDefinitionDto,
  UpdateFormDefinitionDto,
  QueryFormDefinitionDto,
  PublishFormDefinitionDto,
  ArchiveFormDefinitionDto,
  CopyFormDefinitionDto,
} from '../dto';
import { FormIdentifierResolverService } from './form-identifier-resolver.service';
import * as crypto from 'crypto';

@Injectable()
export class FormDefinitionService {
  private readonly logger = new Logger(FormDefinitionService.name);

  constructor(
    private readonly prisma: PrismaService,
    private readonly identifierResolver: FormIdentifierResolverService
  ) {}

  // ============================================
  // 1. 创建表单定义
  // ============================================

  async create(dto: CreateFormDefinitionDto, createdBy: string) {
    this.logger.log(`Creating form definition with slug: ${dto.slug}, createdBy: ${createdBy}`);

    // 检查 slug 是否已存在
    const existingBySlug = await this.prisma.formDefinition.findUnique({
      where: { slug: dto.slug },
    });
    if (existingBySlug) {
      throw new ConflictException({
        code: 'SLUG_ALREADY_EXISTS',
        message: `Form with slug "${dto.slug}" already exists`,
      });
    }

    // 检查 key 是否已存在（如果提供了）
    const key = dto.key || this.generateFormKey();
    const existingByKey = await this.prisma.formDefinition.findUnique({
      where: { key },
    });
    if (existingByKey) {
      throw new ConflictException({
        code: 'KEY_ALREADY_EXISTS',
        message: `Form with key "${key}" already exists`,
      });
    }

    // 检查 aliases 是否与现有表单冲突
    if (dto.aliases && dto.aliases.length > 0) {
      await this.checkAliasesConflict(dto.aliases);
    }

    // 创建表单定义和初始版本
    const formDefinition = await this.prisma.formDefinition.create({
      data: {
        key,
        slug: dto.slug,
        name: dto.nameI18n[dto.defaultLocale] || Object.values(dto.nameI18n)[0],
        category: dto.category,
        description: dto.descriptionI18n?.[dto.defaultLocale],
        icon: dto.icon,
        color: dto.color,
        defaultLocale: dto.defaultLocale,
        supportedLocales: dto.supportedLocales,
        status: FormStatus.DRAFT, // 应用层默认值
        requiresApproval: dto.requiresApproval,
        approvalProcessKey: dto.approvalProcessKey,
        latestVersion: 1, // 应用层默认值
        aliases: dto.aliases || [],
        slugHistory: [],
        creator: {
          connect: { id: createdBy },
        },
        versions: {
          create: {
            version: 1,
            schema: dto.schema,
            uiSchema: dto.uiSchema,
            validation: dto.validation,
            nameI18n: dto.nameI18n,
            descriptionI18n: dto.descriptionI18n,
            status: FormVersionStatus.DRAFT, // 应用层默认值
            isDefault: true, // 应用层默认值
            creator: {
              connect: { id: createdBy },
            },
          },
        },
      },
      include: {
        versions: true,
        _count: {
          select: {
            versions: true,
            instances: true,
          },
        },
      },
    });

    // 创建翻译数据（如果提供了）
    if (dto.translations) {
      const translationPromises = Object.entries(dto.translations).map(
        ([locale, translations]) =>
          this.prisma.formTranslation.create({
            data: {
              versionId: formDefinition.versions[0].id,
              locale,
              translations,
            },
          })
      );
      await Promise.all(translationPromises);
    }

    this.logger.log(`Form definition created: ${formDefinition.id}`);
    return this.formatFormDefinitionResponse(formDefinition);
  }

  // ============================================
  // 2. 获取表单定义列表
  // ============================================

  async findAll(query: QueryFormDefinitionDto, userId?: string) {
    const {
      category,
      status,
      requiresApproval,
      search,
      page = 1,
      limit = 20,
    } = query;

    const where: Prisma.FormDefinitionWhereInput = {};

    if (category) {
      where.category = category;
    }

    if (status) {
      where.status = status;
    }

    if (requiresApproval !== undefined) {
      where.requiresApproval = requiresApproval;
    }

    if (search) {
      where.OR = [
        { name: { contains: search, mode: 'insensitive' } },
        { key: { contains: search, mode: 'insensitive' } },
        { slug: { contains: search, mode: 'insensitive' } },
        { description: { contains: search, mode: 'insensitive' } },
      ];
    }

    const [items, total] = await Promise.all([
      this.prisma.formDefinition.findMany({
        where,
        skip: (page - 1) * limit,
        take: limit,
        orderBy: { createdAt: 'desc' },
        include: {
          _count: {
            select: {
              versions: true,
              instances: true,
            },
          },
        },
      }),
      this.prisma.formDefinition.count({ where }),
    ]);

    return {
      items: items.map((form) => this.formatFormDefinitionResponse(form)),
      total,
      page,
      limit,
      totalPages: Math.ceil(total / limit),
    };
  }

  // ============================================
  // 3. 获取单个表单定义
  // ============================================

  async findOne(identifier: string) {
    const form = await this.identifierResolver.resolveFormDefinitionWithOptions(identifier,
      {
        versions: {
          orderBy: { version: 'desc' },
        },
        _count: {
          select: {
            versions: true,
            instances: true,
          },
        },
      }
    );

    return this.formatFormDefinitionResponse(form);
  }

  // ============================================
  // 4. 获取表单定义（带默认版本）
  // ============================================

  async findOneWithDefaultVersion(identifier: string) {
    const form = await this.identifierResolver.resolveFormDefinitionWithOptions(identifier,
      {
        versions: {
          where: { isDefault: true, status: FormVersionStatus.PUBLISHED },
          orderBy: { version: 'desc' },
          take: 1,
          include: {
            translations: true,
          },
        },
      }
    ) as any;

    if (!form.versions || form.versions.length === 0) {
      throw new NotFoundException({
        code: 'NO_DEFAULT_VERSION',
        message: `No default published version found for form "${identifier}"`,
      });
    }

    return {
      ...this.formatFormDefinitionResponse(form),
      defaultVersion: form.versions[0],
    };
  }

  // ============================================
  // 5. 更新表单定义
  // ============================================

  async update(
    identifier: string,
    dto: UpdateFormDefinitionDto,
    updatedBy: string
  ) {
    this.logger.log(`Updating form definition: ${identifier}`);

    const form = await this.identifierResolver.resolveFormDefinition(identifier
    ) as any;

    // 提取非数据库字段
    const { nameI18n, descriptionI18n, ...dbFields } = dto;

    // 检查 slug 冲突（如果要修改 slug）
    let slugHistory = form.slugHistory as string[] || [];
    if (dbFields.slug && dbFields.slug !== form.slug) {
      const existingBySlug = await this.prisma.formDefinition.findUnique({
        where: { slug: dbFields.slug },
      });
      if (existingBySlug) {
        throw new ConflictException({
          code: 'SLUG_ALREADY_EXISTS',
          message: `Form with slug "${dbFields.slug}" already exists`,
        });
      }

      // 将旧 slug 加入 slugHistory
      slugHistory = [...slugHistory, form.slug];
    }

    // 检查 aliases 冲突（如果要修改 aliases）
    if (dbFields.aliases) {
      await this.checkAliasesConflict(dbFields.aliases, form.id);
    }

    // 更新多语言名称
    let name = form.name;
    if (nameI18n) {
      const defaultLocale = dbFields.defaultLocale || form.defaultLocale;
      name = nameI18n[defaultLocale] || Object.values(nameI18n)[0];
    }

    // 更新多语言描述
    let description = form.description;
    if (descriptionI18n) {
      const defaultLocale = dbFields.defaultLocale || form.defaultLocale;
      description = descriptionI18n[defaultLocale];
    }

    const updated = await this.prisma.formDefinition.update({
      where: { id: form.id },
      data: {
        ...dbFields,
        name,
        description,
        slugHistory,
        updatedBy,
      },
      include: {
        versions: {
          orderBy: { version: 'desc' },
        },
        _count: {
          select: {
            versions: true,
            instances: true,
          },
        },
      },
    });

    this.logger.log(`Form definition updated: ${updated.id}`);
    return this.formatFormDefinitionResponse(updated);
  }

  // ============================================
  // 5.1 更新 Slug（独立端点）
  // ============================================

  async updateSlug(identifier: string, newSlug: string, updatedBy: string) {
    this.logger.log(`Updating slug for form: ${identifier} to ${newSlug}`);

    const form = await this.identifierResolver.resolveFormDefinition(identifier) as any;

    // 检查新 slug 是否已存在
    if (newSlug !== form.slug) {
      const existingBySlug = await this.prisma.formDefinition.findUnique({
        where: { slug: newSlug },
      });
      if (existingBySlug) {
        throw new ConflictException({
          code: 'SLUG_ALREADY_EXISTS',
          message: `Form with slug "${newSlug}" already exists`,
        });
      }
    }

    // 将旧 slug 加入历史
    const slugHistory = [...(form.slugHistory as string[] || []), form.slug];

    const updated = await this.prisma.formDefinition.update({
      where: { id: form.id },
      data: {
        slug: newSlug,
        slugHistory,
        updatedBy,
      },
      include: {
        _count: {
          select: {
            versions: true,
            instances: true,
          },
        },
      },
    });

    this.logger.log(`Slug updated for form: ${updated.id}`);
    return this.formatFormDefinitionResponse(updated);
  }

  // ============================================
  // 5.2 添加别名
  // ============================================

  async addAliases(identifier: string, newAliases: string[], updatedBy: string) {
    this.logger.log(`Adding aliases to form: ${identifier}`);

    const form = await this.identifierResolver.resolveFormDefinition(identifier) as any;

    // 检查新别名是否冲突
    await this.checkAliasesConflict(newAliases, form.id);

    // 合并别名（去重）
    const currentAliases = (form.aliases as string[]) || [];
    const mergedAliases = [...new Set([...currentAliases, ...newAliases])];

    const updated = await this.prisma.formDefinition.update({
      where: { id: form.id },
      data: {
        aliases: mergedAliases,
        updatedBy,
      },
      include: {
        _count: {
          select: {
            versions: true,
            instances: true,
          },
        },
      },
    });

    this.logger.log(`Aliases added to form: ${updated.id}`);
    return this.formatFormDefinitionResponse(updated);
  }

  // ============================================
  // 5.3 删除别名
  // ============================================

  async removeAlias(identifier: string, aliasToRemove: string, updatedBy: string) {
    this.logger.log(`Removing alias from form: ${identifier}`);

    const form = await this.identifierResolver.resolveFormDefinition(identifier) as any;

    const currentAliases = (form.aliases as string[]) || [];
    const filteredAliases = currentAliases.filter(a => a !== aliasToRemove);

    const updated = await this.prisma.formDefinition.update({
      where: { id: form.id },
      data: {
        aliases: filteredAliases,
        updatedBy,
      },
      include: {
        _count: {
          select: {
            versions: true,
            instances: true,
          },
        },
      },
    });

    this.logger.log(`Alias removed from form: ${updated.id}`);
    return this.formatFormDefinitionResponse(updated);
  }

  // ============================================
  // 6. 删除表单定义
  // ============================================

  async remove(identifier: string) {
    this.logger.log(`Deleting form definition: ${identifier}`);

    const form = await this.identifierResolver.resolveFormDefinitionWithOptions(identifier,
      {
        _count: {
          select: { instances: true },
        },
      }
    ) as any;

    // 检查是否有关联的表单实例
    if (form._count.instances > 0) {
      throw new BadRequestException({
        code: 'FORM_HAS_INSTANCES',
        message: `Cannot delete form "${identifier}" because it has ${form._count.instances} instances. Archive it instead.`,
      });
    }

    await this.prisma.formDefinition.delete({
      where: { id: form.id },
    });

    this.logger.log(`Form definition deleted: ${form.id}`);
    return {
      id: form.id,
      key: form.key,
      slug: form.slug,
      deleted: true,
    };
  }

  // ============================================
  // 7. 归档表单定义
  // ============================================

  async archive(identifier: string, dto?: ArchiveFormDefinitionDto) {
    this.logger.log(`Archiving form definition: ${identifier}`);

    const form = await this.identifierResolver.resolveFormDefinition(identifier
    ) as any;

    const updated = await this.prisma.formDefinition.update({
      where: { id: form.id },
      data: {
        status: FormStatus.ARCHIVED,
      },
      include: {
        _count: {
          select: {
            versions: true,
            instances: true,
          },
        },
      },
    });

    this.logger.log(`Form definition archived: ${form.id}`);
    return this.formatFormDefinitionResponse(updated);
  }

  // ============================================
  // 8. 发布表单定义
  // ============================================

  async publish(identifier: string, dto?: PublishFormDefinitionDto) {
    this.logger.log(`Publishing form definition: ${identifier}`);

    const form = await this.identifierResolver.resolveFormDefinitionWithOptions(identifier,
      {
        versions: {
          where: { status: FormVersionStatus.PUBLISHED, isDefault: true },
        },
      }
    ) as any;

    // 检查是否有已发布且设为默认的版本
    if (!form.versions || form.versions.length === 0) {
      throw new BadRequestException({
        code: 'FORM_NOT_PUBLISHABLE',
        message:
          'Form cannot be published because it has no published and default version',
      });
    }

    const updated = await this.prisma.formDefinition.update({
      where: { id: form.id },
      data: {
        status: FormStatus.PUBLISHED,
      },
      include: {
        _count: {
          select: {
            versions: true,
            instances: true,
          },
        },
      },
    });

    this.logger.log(`Form definition published: ${form.id}`);
    return this.formatFormDefinitionResponse(updated);
  }

  // ============================================
  // 9. 获取表单统计信息（Admin Only）
  // ============================================

  async getStats(identifier: string) {
    const form = await this.identifierResolver.resolveFormDefinition(identifier
    ) as any;

    const [
      totalInstances,
      draftCount,
      submittedCount,
      approvedCount,
      rejectedCount,
      cancelledCount,
      lastSubmitted,
    ] = await Promise.all([
      this.prisma.formInstance.count({
        where: { formDefinitionId: form.id, deletedAt: null },
      }),
      this.prisma.formInstance.count({
        where: {
          formDefinitionId: form.id,
          status: 'DRAFT',
          deletedAt: null,
        },
      }),
      this.prisma.formInstance.count({
        where: {
          formDefinitionId: form.id,
          status: 'SUBMITTED',
          deletedAt: null,
        },
      }),
      this.prisma.formInstance.count({
        where: {
          formDefinitionId: form.id,
          status: 'APPROVED',
          deletedAt: null,
        },
      }),
      this.prisma.formInstance.count({
        where: {
          formDefinitionId: form.id,
          status: 'REJECTED',
          deletedAt: null,
        },
      }),
      this.prisma.formInstance.count({
        where: {
          formDefinitionId: form.id,
          status: 'CANCELLED',
          deletedAt: null,
        },
      }),
      this.prisma.formInstance.findFirst({
        where: {
          formDefinitionId: form.id,
          status: 'SUBMITTED',
          deletedAt: null,
        },
        orderBy: { submittedAt: 'desc' },
        select: { submittedAt: true },
      }),
    ]);

    const submittedTotal = submittedCount + approvedCount + rejectedCount;
    const submissionRate =
      totalInstances > 0 ? submittedTotal / totalInstances : 0;

    // 计算平均完成时间（从创建到提交）
    const completedInstances = await this.prisma.formInstance.findMany({
      where: {
        formDefinitionId: form.id,
        status: { in: ['SUBMITTED', 'APPROVED', 'REJECTED'] },
        submittedAt: { not: null },
        deletedAt: null,
      },
      select: {
        createdAt: true,
        submittedAt: true,
      },
      take: 100, // 取最近100条计算平均值
    });

    let averageCompletionTime = 0;
    if (completedInstances.length > 0) {
      const totalTime = completedInstances.reduce((sum, instance) => {
        const duration =
          (instance.submittedAt ? new Date(instance.submittedAt).getTime() : 0) -
          new Date(instance.createdAt).getTime();
        return sum + duration / 1000; // 转换为秒
      }, 0);
      averageCompletionTime = Math.round(
        totalTime / completedInstances.length
      );
    }

    return {
      formId: form.id,
      totalInstances,
      draftCount,
      submittedCount,
      approvedCount,
      rejectedCount,
      cancelledCount,
      submissionRate: Math.round(submissionRate * 100) / 100,
      averageCompletionTime,
      lastSubmittedAt: lastSubmitted?.submittedAt || null,
    };
  }

  // ============================================
  // 10. 复制表单定义
  // ============================================

  async copy(
    identifier: string,
    dto: CopyFormDefinitionDto,
    createdBy: string
  ) {
    this.logger.log(`Copying form definition: ${identifier}`);

    const sourceForm =
      await this.identifierResolver.resolveFormDefinitionWithOptions(
        identifier,
        {
          versions: dto.copyAllVersions
            ? {
                orderBy: { version: 'asc' },
                include: { translations: true },
              }
            : {
                where: { isDefault: true },
                include: { translations: true },
              },
        }
      ) as any;

    if (!sourceForm.versions || sourceForm.versions.length === 0) {
      throw new NotFoundException(
        `No versions found for form "${identifier}"`
      );
    }

    // 检查新 slug 是否已存在
    const existingBySlug = await this.prisma.formDefinition.findUnique({
      where: { slug: dto.newSlug },
    });
    if (existingBySlug) {
      throw new ConflictException({
        code: 'SLUG_ALREADY_EXISTS',
        message: `Form with slug "${dto.newSlug}" already exists`,
      });
    }

    // 生成新的 key
    const newKey = this.generateFormKey();

    // 提取新名称
    const newName =
      dto.newName[sourceForm.defaultLocale] || Object.values(dto.newName)[0];

    // 创建新表单定义
    const newForm = await this.prisma.formDefinition.create({
      data: {
        key: newKey,
        slug: dto.newSlug,
        name: newName,
        category: sourceForm.category,
        description: sourceForm.description,
        icon: sourceForm.icon,
        color: sourceForm.color,
        defaultLocale: sourceForm.defaultLocale,
        supportedLocales: sourceForm.supportedLocales as any,
        status: FormStatus.DRAFT,
        requiresApproval: sourceForm.requiresApproval,
        approvalProcessKey: sourceForm.approvalProcessKey,
        latestVersion: sourceForm.versions.length,
        aliases: [],
        slugHistory: [],
        createdBy,
      },
    });

    // 复制版本
    for (const [index, sourceVersion] of sourceForm.versions.entries()) {
      const newVersion = await this.prisma.formVersion.create({
        data: {
          definitionId: newForm.id,
          version: index + 1,
          schema: sourceVersion.schema,
          uiSchema: sourceVersion.uiSchema,
          validation: sourceVersion.validation,
          nameI18n: index === 0 ? dto.newName : sourceVersion.nameI18n,
          descriptionI18n: sourceVersion.descriptionI18n,
          changelog: sourceVersion.changelog,
          status: FormVersionStatus.DRAFT,
          isDefault: index === 0,
          createdBy,
        },
      });

      // 复制翻译
      if (sourceVersion.translations && sourceVersion.translations.length > 0) {
        const translationPromises = sourceVersion.translations.map(
          (translation: any) =>
            this.prisma.formTranslation.create({
              data: {
                versionId: newVersion.id,
                locale: translation.locale,
                translations: translation.translations,
              },
            })
        );
        await Promise.all(translationPromises);
      }
    }

    // 查询完整的新表单
    const newFormComplete = await this.prisma.formDefinition.findUnique({
      where: { id: newForm.id },
      include: {
        versions: {
          orderBy: { version: 'desc' },
        },
        _count: {
          select: {
            versions: true,
            instances: true,
          },
        },
      },
    });

    this.logger.log(`Form definition copied: ${newForm.id}`);
    return this.formatFormDefinitionResponse(newFormComplete);
  }

  // ============================================
  // 私有辅助方法
  // ============================================

  /**
   * 生成唯一的表单 key
   */
  private generateFormKey(): string {
    const timestamp = Date.now().toString(36);
    const randomStr = crypto.randomBytes(4).toString('hex');
    return `form_${timestamp}_${randomStr}`;
  }

  /**
   * 检查 aliases 是否与现有表单冲突
   */
  private async checkAliasesConflict(
    aliases: string[],
    excludeId?: string
  ): Promise<void> {
    for (const alias of aliases) {
      // 检查是否与 key 冲突
      const existingByKey = await this.prisma.formDefinition.findUnique({
        where: { key: alias },
      });
      if (existingByKey && existingByKey.id !== excludeId) {
        throw new ConflictException({
          code: 'ALIAS_ALREADY_EXISTS',
          message: `Alias "${alias}" conflicts with an existing form key`,
        });
      }

      // 检查是否与 slug 冲突
      const existingBySlug = await this.prisma.formDefinition.findUnique({
        where: { slug: alias },
      });
      if (existingBySlug && existingBySlug.id !== excludeId) {
        throw new ConflictException({
          code: 'ALIAS_ALREADY_EXISTS',
          message: `Alias "${alias}" conflicts with an existing form slug`,
        });
      }

      // 检查是否与其他表单的 aliases 冲突
      // 注意：path: ['$'] 是 MongoDB jsonpath，PG 下查不到任何记录；用 array_contains 直接对应 PG `@>`
      const existingByAlias = await this.prisma.formDefinition.findFirst({
        where: {
          aliases: { array_contains: alias },
        },
      });
      if (existingByAlias && existingByAlias.id !== excludeId) {
        throw new ConflictException({
          code: 'ALIAS_ALREADY_EXISTS',
          message: `Alias "${alias}" already exists in another form`,
        });
      }
    }
  }

  /**
   * 格式化表单定义响应
   */
  private formatFormDefinitionResponse(form: any) {
    const { _count, ...formData } = form;

    return {
      ...formData,
      versionCount: _count?.versions || 0,
      instanceCount: _count?.instances || 0,
    };
  }
}
