import { DataSource, Repository, ObjectLiteral, DeepPartial, In } from 'typeorm';
import { z } from '@hono/zod-openapi';
import { DataPermissionOptions, validateDataPermissionOptions, PermissionError } from '../types/data-permission.types';

export abstract class GenericCrudService<T extends ObjectLiteral> {
  public repository: Repository<T>;
  private userTrackingOptions?: UserTrackingOptions;
  private dataPermissionOptions?: DataPermissionOptions;
  private tenantOptions?: TenantOptions;

  protected relationFields?: RelationFieldOptions;

  constructor(
    protected dataSource: DataSource,
    protected entity: new () => T,
    options?: {
      userTracking?: UserTrackingOptions;
      relationFields?: RelationFieldOptions;
      dataPermission?: DataPermissionOptions;
      tenantOptions?: TenantOptions;
    }
  ) {
    this.repository = this.dataSource.getRepository(entity);
    this.userTrackingOptions = options?.userTracking;
    this.relationFields = options?.relationFields;

    // 验证并设置数据权限配置
    if (options?.dataPermission) {
      validateDataPermissionOptions(options.dataPermission);
      this.dataPermissionOptions = options.dataPermission;
    }

    // 设置租户选项
    this.tenantOptions = options?.tenantOptions;
  }

  /**
   * 获取分页列表
   */
  async getList(
    page: number = 1,
    pageSize: number = 10,
    keyword?: string,
    searchFields?: string[],
    where?: Partial<T>,
    relations: string[] = [],
    order: { [P in keyof T]?: 'ASC' | 'DESC' } = {},
    filters?: {
      [key: string]: any;
    },
    userId?: string | number
  ): Promise<[T[], number]> {
    const skip = (page - 1) * pageSize;
    const query = this.repository.createQueryBuilder('entity');

    // 添加数据权限过滤
    if (this.dataPermissionOptions?.enabled && userId) {
      const userIdField = this.dataPermissionOptions.userIdField;
      query.andWhere(`entity.${userIdField} = :userId`, { userId });
    }

    // 添加租户隔离过滤
    if (this.tenantOptions?.enabled) {
      const tenantIdField = this.tenantOptions.tenantIdField || 'tenantId';
      const tenantId = await this.extractTenantId(userId);
      if (tenantId !== undefined && tenantId !== null) {
        query.andWhere(`entity.${tenantIdField} = :tenantId`, { tenantId });
      }
    }

    // 添加关联关系（支持嵌套关联，如 ['contract.client']）
    // 使用一致的别名生成策略，确保搜索时能正确引用关联字段
    if (relations.length > 0) {
      relations.forEach((relation) => {
        const parts = relation.split('.');
        let currentAlias = 'entity';

        parts.forEach((part, index) => {
          // 生成一致的别名：对于嵌套关联，使用下划线连接路径
          const newAlias = index === 0 ? part : parts.slice(0, index + 1).join('_');
          query.leftJoinAndSelect(`${currentAlias}.${part}`, newAlias);
          currentAlias = newAlias;
        });
      });
    }

    // 关键词搜索 - 支持关联字段搜索（格式：relation.field 或 relation.nestedRelation.field）
    if (keyword && searchFields && searchFields.length > 0) {
      const searchConditions: string[] = [];
      const searchParams: Record<string, string> = { keyword: `%${keyword}%` };

      searchFields.forEach((field) => {
        // 检查是否为关联字段（包含点号）
        if (field.includes('.')) {
          const parts = field.split('.');
          const alias = parts.slice(0, -1).join('_'); // 使用下划线连接关系路径作为别名
          const fieldName = parts[parts.length - 1];

          searchConditions.push(`${alias}.${fieldName} LIKE :keyword`);
        } else {
          // 普通字段搜索
          searchConditions.push(`entity.${field} LIKE :keyword`);
        }
      });

      if (searchConditions.length > 0) {
        query.andWhere(`(${searchConditions.join(' OR ')})`, searchParams);
      }
    }

    // 条件查询
    if (where) {
      Object.entries(where).forEach(([key, value]) => {
        if (value !== undefined && value !== null) {
          query.andWhere(`entity.${key} = :${key}`, { [key]: value });
        }
      });
    }

    // 扩展筛选条件
    if (filters) {
      Object.entries(filters).forEach(([key, value]) => {
        if (value !== undefined && value !== null && value !== '') {
          const fieldName = key.startsWith('_') ? key.substring(1) : key;

          // 检查是否为关联字段（包含点号）
          let tableAlias: string = 'entity';
          let actualFieldName: string = fieldName;

          if (fieldName.includes('.')) {
            const parts = fieldName.split('.');
            tableAlias = parts.slice(0, -1).join('_') || 'entity'; // 使用下划线连接关系路径作为别名
            actualFieldName = parts[parts.length - 1] || fieldName;
          }

          // 支持不同类型的筛选
          if (Array.isArray(value)) {
            // 数组类型：IN查询
            if (value.length > 0) {
              query.andWhere(`${tableAlias}.${actualFieldName} IN (:...${key})`, { [key]: value });
            }
          } else if (typeof value === 'string' && value.includes('%')) {
            // 模糊匹配
            query.andWhere(`${tableAlias}.${actualFieldName} LIKE :${key}`, { [key]: value });
          } else if (typeof value === 'object' && value !== null) {
            // 范围查询
            if ('gte' in value) {
              query.andWhere(`${tableAlias}.${actualFieldName} >= :${key}_gte`, { [`${key}_gte`]: value.gte });
            }
            if ('gt' in value) {
              query.andWhere(`${tableAlias}.${actualFieldName} > :${key}_gt`, { [`${key}_gt`]: value.gt });
            }
            if ('lte' in value) {
              query.andWhere(`${tableAlias}.${actualFieldName} <= :${key}_lte`, { [`${key}_lte`]: value.lte });
            }
            if ('lt' in value) {
              query.andWhere(`${tableAlias}.${actualFieldName} < :${key}_lt`, { [`${key}_lt`]: value.lt });
            }
            if ('between' in value && Array.isArray(value.between) && value.between.length === 2) {
              query.andWhere(`${tableAlias}.${actualFieldName} BETWEEN :${key}_start AND :${key}_end`, {
                [`${key}_start`]: value.between[0],
                [`${key}_end`]: value.between[1]
              });
            }
          } else {
            // 精确匹配
            query.andWhere(`${tableAlias}.${actualFieldName} = :${key}`, { [key]: value });
          }
        }
      });
    }

    // 排序
    Object.entries(order).forEach(([key, direction]) => {
      query.orderBy(`entity.${key}`, direction);
    });

    const finalQuery = query.skip(skip).take(pageSize);

    // console.log(finalQuery.getSql())

    return finalQuery.getManyAndCount();
  }

  /**
   * 根据ID获取单个实体
   */
  async getById(id: number, relations: string[] = [], userId?: string | number): Promise<T | null> {
    const entity = await this.repository.findOne({
      where: { id } as any,
      relations
    });

    if (!entity) {
      return null;
    }

    // 租户隔离验证 - 先于数据权限验证
    if (this.tenantOptions?.enabled) {
      const tenantIdField = this.tenantOptions.tenantIdField || 'tenantId';
      const tenantId = await this.extractTenantId(userId);
      if (tenantId !== undefined && tenantId !== null) {
        const entityTenantId = (entity as any)[tenantIdField];
        if (entityTenantId !== tenantId) {
          return null; // 不属于当前租户，返回null
        }
      }
    }

    // 数据权限验证
    if (this.dataPermissionOptions?.enabled && userId) {
      const hasPermission = await this.checkPermission(entity, userId);
      if (!hasPermission) {
        throw new PermissionError('没有权限访问该资源');
      }
    }

    return entity;
  }

  /**
   * 检查用户对实体的权限
   */
  private async checkPermission(entity: any, userId: string | number): Promise<boolean> {
    const options = this.dataPermissionOptions;
    if (!options?.enabled) return true;

    // 管理员权限覆盖检查
    if (options.adminOverride?.enabled && options.adminOverride.adminRole) {
      // 这里需要从认证系统获取用户角色信息
      // 暂时假设管理员可以访问所有数据
      // 实际实现中需要集成用户角色检查
      const isAdmin = await this.checkAdminRole(userId, options.adminOverride.adminRole);
      if (isAdmin) {
        return true;
      }
    }

    // 自定义权限验证器
    if (options.customValidator) {
      return await options.customValidator(userId, entity);
    }

    // 基础权限验证：用户ID字段匹配
    const userIdField = options.userIdField;
    const entityUserId = entity[userIdField];
    return entityUserId === userId;
  }

  /**
   * 检查用户是否为管理员
   * TODO: 需要集成实际的用户角色检查
   */
  private async checkAdminRole(_userId: string | number, _adminRole: string): Promise<boolean> {
    // 这里需要从认证系统获取用户角色信息
    // 暂时返回false，实际实现中需要集成用户角色检查
    return false;
  }

  /**
   * 提取租户ID
   * 从用户对象或认证上下文中提取租户ID
   */
  private async extractTenantId(_userId?: string | number): Promise<string | number | undefined> {
    // 首先检查是否有存储的租户上下文
    if ((this as any)._tenantId !== undefined) {
      console.debug('从存储的租户上下文中获取租户ID:', (this as any)._tenantId);
      return (this as any)._tenantId;
    }

    // 如果租户选项启用了从上下文自动提取，则从上下文获取
    if (this.tenantOptions?.autoExtractFromContext) {
      // 这里需要从Hono上下文中获取租户ID
      // 在实际实现中，认证中间件应该设置租户上下文
      // 暂时返回undefined，实际实现中需要认证中间件设置tenantId
      console.debug('autoExtractFromContext为true，但未实现从Hono上下文获取租户ID');
      return undefined;
    }

    // 如果用户对象包含租户ID字段，则从用户对象中提取
    // 这里需要实际的用户对象，暂时返回undefined
    console.debug('没有找到租户ID，返回undefined');
    return undefined;
  }

  /**
   * 设置租户上下文
   * 用于从外部传递租户ID
   */
  setTenantContext(tenantId: string | number): void {
    // 存储租户上下文
    (this as any)._tenantId = tenantId;
    console.debug('设置租户上下文:', tenantId);
  }

  /**
   * 设置租户字段
   */
  private async setTenantFields(data: any, userId?: string | number): Promise<void> {
    if (!this.tenantOptions?.enabled) {
      return;
    }

    const tenantIdField = this.tenantOptions.tenantIdField || 'tenantId';
    const tenantId = await this.extractTenantId(userId);

    // 只有在数据中不存在租户ID字段时才设置
    if (tenantId !== undefined && tenantId !== null && !data[tenantIdField]) {
      data[tenantIdField] = tenantId;
    }
  }

  /**
   * 设置用户跟踪字段
   */
  private setUserFields(data: any, userId?: string | number, isCreate: boolean = true): void {
    if (!this.userTrackingOptions || !userId) {
      return;
    }

    const {
      createdByField = 'createdBy',
      updatedByField = 'updatedBy',
      userIdField = 'userId'
    } = this.userTrackingOptions;

    // 设置创建人
    // 只有在数据中不存在该字段时才设置，避免覆盖管理员传入的用户ID
    if (isCreate && createdByField && !data[createdByField]) {
      data[createdByField] = userId;
    }

    // 设置更新人
    if (updatedByField) {
      data[updatedByField] = userId;
    }

    // 设置关联的用户ID（如userId字段）
    // 只有在数据中不存在该字段时才设置，避免覆盖管理员传入的用户ID
    if (isCreate && userIdField && !data[userIdField]) {
      data[userIdField] = userId;
    }
  }

  /**
   * 处理关联字段
   */
  private async handleRelationFields(data: any, entity: T, _isUpdate: boolean = false): Promise<void> {
    if (!this.relationFields) return;

    for (const [fieldName, config] of Object.entries(this.relationFields)) {
      if (data[fieldName] !== undefined) {
        const ids = data[fieldName];
        const relationRepository = this.dataSource.getRepository(config.targetEntity);

        if (ids && Array.isArray(ids) && ids.length > 0) {
          const relatedEntities = await relationRepository.findBy({ id: In(ids) });
          (entity as any)[config.relationName] = relatedEntities;
        } else {
          (entity as any)[config.relationName] = [];
        }

        // 清理原始数据中的关联字段
        delete data[fieldName];
      }
    }
  }

  /**
   * 创建实体
   */
  async create(data: DeepPartial<T>, userId?: string | number): Promise<T> {
    // 权限验证：防止用户创建不属于自己的数据
    if (this.dataPermissionOptions?.enabled && userId) {
      const userIdField = this.dataPermissionOptions.userIdField;

      // 如果数据中已经包含用户ID字段，验证是否与当前用户匹配
      const dataObj = data as any;
      if (dataObj[userIdField] && dataObj[userIdField] !== userId) {
        throw new Error('无权创建该资源');
      }
    }

    const entityData = { ...data };
    this.setUserFields(entityData, userId, true);
    await this.setTenantFields(entityData, userId);

    // 分离关联字段数据
    const relationData: any = {};
    if (this.relationFields) {
      for (const fieldName of Object.keys(this.relationFields)) {
        if (fieldName in entityData) {
          relationData[fieldName] = (entityData as any)[fieldName];
          delete (entityData as any)[fieldName];
        }
      }
    }

    const entity = this.repository.create(entityData as DeepPartial<T>);

    // 处理关联字段
    await this.handleRelationFields(relationData, entity);

    return this.repository.save(entity);
  }

  /**
   * 更新实体
   */
  async update(id: number, data: Partial<T>, userId?: string | number): Promise<T | null> {
    // 权限验证
    if (this.dataPermissionOptions?.enabled && userId) {
      const entity = await this.getById(id);
      if (!entity) return null;

      const hasPermission = await this.checkPermission(entity, userId);
      if (!hasPermission) {
        throw new Error('无权更新该资源');
      }
    }

    // 租户隔离验证
    if (this.tenantOptions?.enabled) {
      const entity = await this.getById(id);
      if (!entity) return null;

      const tenantIdField = this.tenantOptions.tenantIdField || 'tenantId';
      const tenantId = await this.extractTenantId(userId);
      if (tenantId !== undefined && tenantId !== null) {
        const entityTenantId = (entity as any)[tenantIdField];
        if (entityTenantId !== tenantId) {
          return null; // 不属于当前租户，返回null
        }
      }
    }

    const updateData = { ...data };
    this.setUserFields(updateData, userId, false);

    // 分离关联字段数据
    const relationData: any = {};
    if (this.relationFields) {
      for (const fieldName of Object.keys(this.relationFields)) {
        if (fieldName in updateData) {
          relationData[fieldName] = (updateData as any)[fieldName];
          delete (updateData as any)[fieldName];
        }
      }
    }

    // 先更新基础字段
    await this.repository.update(id, updateData);

    // 获取完整实体并处理关联字段
    const entity = await this.getById(id);
    if (!entity) return null;

    // 处理关联字段
    await this.handleRelationFields(relationData, entity, true);

    return this.repository.save(entity);
  }

  /**
   * 删除实体
   */
  async delete(id: number, userId?: string | number): Promise<boolean> {
    // 权限验证
    if (this.dataPermissionOptions?.enabled && userId) {
      const entity = await this.getById(id);
      if (!entity) return false;

      const hasPermission = await this.checkPermission(entity, userId);
      if (!hasPermission) {
        throw new Error('无权删除该资源');
      }
    }

    // 租户隔离验证
    if (this.tenantOptions?.enabled) {
      const entity = await this.getById(id);
      if (!entity) return false;

      const tenantIdField = this.tenantOptions.tenantIdField || 'tenantId';
      const tenantId = await this.extractTenantId(userId);
      if (tenantId !== undefined && tenantId !== null) {
        const entityTenantId = (entity as any)[tenantIdField];
        if (entityTenantId !== tenantId) {
          return false; // 不属于当前租户，返回false
        }
      }
    }

    // 执行删除
    const result = await this.repository.delete(id);
    return result.affected === 1;
  }

  /**
   * 高级查询方法
   */
  createQueryBuilder(alias: string = 'entity') {
    return this.repository.createQueryBuilder(alias);
  }
}

export interface UserTrackingOptions {
  createdByField?: string;
  updatedByField?: string;
  userIdField?: string;
}

export interface RelationFieldOptions {
  [fieldName: string]: {
    relationName: string;
    targetEntity: new () => any;
    joinTableName?: string;
  };
}

export type CrudOptions<
  T extends ObjectLiteral,
  CreateSchema extends z.ZodSchema = z.ZodSchema,
  UpdateSchema extends z.ZodSchema = z.ZodSchema,
  GetSchema extends z.ZodSchema = z.ZodSchema,
  ListSchema extends z.ZodSchema = z.ZodSchema
> = {
  entity: new () => T;
  createSchema: CreateSchema;
  updateSchema: UpdateSchema;
  getSchema: GetSchema;
  listSchema: ListSchema;
  searchFields?: string[];
  relations?: string[];
  middleware?: any[];
  userTracking?: UserTrackingOptions;
  relationFields?: RelationFieldOptions;
  readOnly?: boolean;
  /**
   * 数据权限控制配置
   */
  dataPermission?: DataPermissionOptions;
  /**
   * 默认过滤条件，会在所有查询中应用
   */
  defaultFilters?: Partial<T>;
  /**
   * 租户隔离配置
   */
  tenantOptions?: TenantOptions;
};

export interface TenantOptions {
  /**
   * 租户ID字段名，默认为 'tenantId'
   */
  tenantIdField?: string;
  /**
   * 是否启用租户隔离
   */
  enabled?: boolean;
  /**
   * 是否自动从认证上下文提取租户ID
   */
  autoExtractFromContext?: boolean;
}