import {
  Body,
  Controller,
  Get,
  Post,
  Query,
  UseGuards,
  UsePipes,
  ValidationPipe,
} from '@nestjs/common';
import { ProjectService } from '../project/project.service';
import {
  ApiBearerAuth,
  ApiOkResponse,
  ApiOperation,
  ApiTags,
} from '@nestjs/swagger';
import { CollectProjectDTO, PqDTO } from '../project/dto/project-dto';
import {
  ApiOkResponseListWithTotal,
  ApiResultListWithTotal,
} from '../common/types/api-result';
import { AssetViewDTO } from '../asset/dto/asset-dto';
import {
  AssetViewQueryDTO,
  AssetViewQueryPostDTO,
} from '../asset/dto/asset-query-dto';
import { AssetPropsSelection } from '../asset/logic/PropsSelection';
import { AssetSelectorService } from '../asset/asset-selector.service';
import { MIN_ASSET_RIGHTS_TO_READ } from '../asset/logic/Rights';
import { assignRightsFilterInSelection } from '../asset/logic/assignRightsFilterInSelection';
import { InjectDataSource } from '@nestjs/typeorm';
import { Connection } from 'typeorm';
import { checkProjectAccess } from '../utils/project-access';
import { parsePq } from '../project/project-query';
import { TokenOrJwtAuthGuard } from '../guards/token-or-jwt.auth.guard';
import { RequestUser } from '../common/request-user';
import { UserDTO } from '../dto/user-dto';
import { SYSTEM_USER_ID } from '../common/dto/user-dto';
import {
  convertAssetQueryToPostFormat,
  convertAssetQueryToSelection,
} from '../asset/asset-utils';

@ApiTags('collect')
@Controller('collect')
@UseGuards(TokenOrJwtAuthGuard)
@ApiBearerAuth()
export class CollectController {
  constructor(
    private readonly assetSelectorService: AssetSelectorService,
    private readonly projectService: ProjectService,
    @InjectDataSource()
    private readonly connection: Connection,
  ) {}

  @Get('project')
  @ApiOperation({
    summary: 'Get project collect',
  })
  @ApiOkResponse({
    type: CollectProjectDTO,
  })
  async collectProject(
    @Query() params: PqDTO,
    @RequestUser() account: UserDTO,
  ): Promise<ApiResultListWithTotal<CollectProjectDTO>> {
    const pq = parsePq(params.pq);
    if (account.id !== SYSTEM_USER_ID) {
      pq.my = true;
    }
    const ids = await this.projectService.getProjectIdsByProjectQuery(pq);
    return await this.projectService.collectProject(ids);
  }

  @Get('asset/view')
  @ApiOperation({
    summary: 'Get view asset list',
  })
  @ApiOkResponseListWithTotal(AssetViewDTO)
  @UsePipes(
    new ValidationPipe({
      transform: true,
      transformOptions: { enableImplicitConversion: true },
    }),
  )
  async getCollectAssetsView(
    @Query() filterData: AssetViewQueryDTO,
    @Query() pq: PqDTO,
    @RequestUser() account: UserDTO,
  ): Promise<
    ApiResultListWithTotal<
      ApiResultListWithTotal<AssetViewDTO> & { projectId: string }
    >
  > {
    const filterDataPost = convertAssetQueryToPostFormat(filterData);
    const selection = convertAssetQueryToSelection(filterDataPost);
    return await this._getCollectAssetsView(selection, pq, account);
  }

  @Post('asset/view')
  @ApiOperation({
    summary: 'Get view asset list',
  })
  @ApiOkResponseListWithTotal(AssetViewDTO)
  @UsePipes(
    new ValidationPipe({
      transform: true,
      transformOptions: { enableImplicitConversion: true },
    }),
  )
  async getAssetsViewPost(
    @Body() filterData: AssetViewQueryPostDTO,
    @Query() pq: PqDTO,
    @RequestUser() account: UserDTO,
  ): Promise<
    ApiResultListWithTotal<
      ApiResultListWithTotal<AssetViewDTO> & { projectId: string }
    >
  > {
    const selection = convertAssetQueryToSelection(filterData);
    return await this._getCollectAssetsView(selection, pq, account);
  }

  async _getCollectAssetsView(
    selection: AssetPropsSelection,
    params: PqDTO,
    account: UserDTO,
  ): Promise<
    ApiResultListWithTotal<
      ApiResultListWithTotal<AssetViewDTO> & { projectId: string }
    >
  > {
    const result: ApiResultListWithTotal<
      ApiResultListWithTotal<AssetViewDTO> & { projectId: string }
    > = {
      list: [],
      total: 0,
    };

    const pq = parsePq(params.pq);
    if (account.id !== SYSTEM_USER_ID) {
      pq.my = true;
    }
    const ids = await this.projectService.getProjectIdsByProjectQuery(pq);

    for (const project_id of ids) {
      const project_access = await checkProjectAccess(
        this.connection,
        account.id,
        project_id,
      );

      const asset_view = await this.assetSelectorService.getViewPaginated(
        assignRightsFilterInSelection(selection, MIN_ASSET_RIGHTS_TO_READ),
        project_access,
      );
      result.list.push({ ...asset_view, projectId: project_id });
    }
    result.total = result.list.length;
    return result;
  }
}
