import {
  Body,
  Controller,
  Delete,
  Get,
  Param,
  Patch,
  Post,
  Query,
  Req,
  UseGuards,
} from '@nestjs/common';
import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger';
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
import { AcceptOrganizationInviteDto } from './dto/accept-organization-invite.dto';
import { CreateConnectionRequestDto } from './dto/create-connection-request.dto';
import { InviteOrganizationDto } from './dto/invite-organization.dto';
import { PreviewOrganizationInviteDto } from './dto/preview-organization-invite.dto';
import { RespondConnectionRequestDto } from './dto/respond-connection-request.dto';
import { OrganizationService } from './organization.service';
import { ListLabCasesDto } from '../cases/dto/cases.dto';
import { CreateLabCaseCommentDto } from '../lab-case-comments/dto/lab-case-comment.dto';

/**
 * Counterpart orgs (clinic↔lab).
 *
 * - `/connections` — OrganizationLink rows (connection requests + links created by invites).
 * - `/invite`, `/invitations/*` — signup invitation tokens (orgs not yet on DyoLink).
 */
@ApiTags('organizations')
@ApiBearerAuth('JWT-auth')
@Controller('organizations')
export class OrganizationController {
  constructor(private readonly organizationService: OrganizationService) {}

  @Get('invitations/preview')
  @ApiOperation({ summary: 'Preview organization invite by token (public)' })
  previewInvite(@Query() query: PreviewOrganizationInviteDto) {
    return this.organizationService.previewInvite(query.token);
  }

  @Get('invitations')
  @UseGuards(JwtAuthGuard)
  @ApiOperation({ summary: 'List invitation history for current organization' })
  listInvitations(@Req() req: { user: { id: string; organizationId?: string } }) {
    const organizationId = this.organizationService.getOrganizationIdFromUser(req.user);
    return this.organizationService.listInvitationHistory(req.user.id, organizationId);
  }

  @Post('invitations/accept')
  @ApiOperation({ summary: 'Accept organization invite and create/link counterpart org (public)' })
  acceptInvite(@Body() dto: AcceptOrganizationInviteDto) {
    return this.organizationService.acceptInvite(dto);
  }

  @Get('search')
  @UseGuards(JwtAuthGuard)
  @ApiOperation({
    summary: 'Search counterpart organizations (active subscription only)',
  })
  search(
    @Req() req: { user: { id: string; organizationId?: string } },
    @Query('q') q = '',
  ) {
    const organizationId = this.organizationService.getOrganizationIdFromUser(req.user);
    return this.organizationService.searchCounterpartOrganizations(req.user.id, organizationId, q);
  }

  @Get('connections/pending-count')
  @UseGuards(JwtAuthGuard)
  @ApiOperation({ summary: 'Count incoming pending connection requests for sidebar badge' })
  countPendingConnections(@Req() req: { user: { id: string; organizationId?: string } }) {
    const organizationId = this.organizationService.getOrganizationIdFromUser(req.user);
    return this.organizationService.countIncomingPendingConnections(req.user.id, organizationId);
  }

  @Get('connections')
  @UseGuards(JwtAuthGuard)
  @ApiOperation({ summary: 'List counterpart connections for current organization' })
  listConnections(@Req() req: { user: { id: string; organizationId?: string } }) {
    const organizationId = this.organizationService.getOrganizationIdFromUser(req.user);
    return this.organizationService.list(req.user.id, organizationId);
  }

  @Post('connections')
  @UseGuards(JwtAuthGuard)
  @ApiOperation({
    summary: 'Create pending connection request to an existing subscribed counterpart org',
  })
  createConnectionRequest(
    @Req() req: { user: { id: string; organizationId?: string } },
    @Body() dto: CreateConnectionRequestDto,
  ) {
    const organizationId = this.organizationService.getOrganizationIdFromUser(req.user);
    return this.organizationService.createConnectionRequest(req.user.id, organizationId, dto);
  }

  @Patch('connections/:connectionId/respond')
  @UseGuards(JwtAuthGuard)
  @ApiOperation({ summary: 'Accept or reject a pending connection request for current organization' })
  respondToConnectionRequest(
    @Req() req: { user: { id: string; organizationId?: string } },
    @Param('connectionId') connectionId: string,
    @Body() dto: RespondConnectionRequestDto,
  ) {
    const organizationId = this.organizationService.getOrganizationIdFromUser(req.user);
    return this.organizationService.respondToConnectionRequest(
      req.user.id,
      organizationId,
      connectionId,
      dto,
    );
  }

  @Delete('connections/:connectionId')
  @UseGuards(JwtAuthGuard)
  @ApiOperation({ summary: 'Remove an active connection' })
  deleteConnection(
    @Req() req: { user: { id: string; organizationId?: string } },
    @Param('connectionId') connectionId: string,
  ) {
    const organizationId = this.organizationService.getOrganizationIdFromUser(req.user);
    return this.organizationService.deleteConnection(req.user.id, organizationId, connectionId);
  }

  @Get('connections/:connectionId/cases')
  @UseGuards(JwtAuthGuard)
  @ApiOperation({ summary: 'List cases exchanged with a connected organization' })
  listConnectionCases(
    @Req() req: { user: { id: string; organizationId?: string } },
    @Param('connectionId') connectionId: string,
    @Query() query: ListLabCasesDto,
  ) {
    const organizationId = this.organizationService.getOrganizationIdFromUser(req.user);
    return this.organizationService.listConnectionCases(
      req.user.id,
      organizationId,
      connectionId,
      query,
    );
  }

  @Get('connections/:connectionId/cases/:caseId')
  @UseGuards(JwtAuthGuard)
  @ApiOperation({ summary: 'Get one case exchanged with a connected organization' })
  getConnectionCase(
    @Req() req: { user: { id: string; organizationId?: string; language?: string | null } },
    @Param('connectionId') connectionId: string,
    @Param('caseId') caseId: string,
  ) {
    const organizationId = this.organizationService.getOrganizationIdFromUser(req.user);
    return this.organizationService.getConnectionCase(
      req.user.id,
      organizationId,
      connectionId,
      caseId,
      req.user.language,
    );
  }

  @Get('connections/:connectionId/cases/:caseId/comments')
  @UseGuards(JwtAuthGuard)
  @ApiOperation({ summary: 'List clinic-visible comments for a connection case' })
  listConnectionCaseComments(
    @Req() req: { user: { id: string; organizationId?: string } },
    @Param('connectionId') connectionId: string,
    @Param('caseId') caseId: string,
  ) {
    const organizationId = this.organizationService.getOrganizationIdFromUser(req.user);
    return this.organizationService.listConnectionCaseComments(
      req.user.id,
      organizationId,
      connectionId,
      caseId,
    );
  }

  @Post('connections/:connectionId/cases/:caseId/comments')
  @UseGuards(JwtAuthGuard)
  @ApiOperation({ summary: 'Reply to a connection case as the clinic' })
  addConnectionCaseComment(
    @Req() req: { user: { id: string; organizationId?: string } },
    @Param('connectionId') connectionId: string,
    @Param('caseId') caseId: string,
    @Body() dto: CreateLabCaseCommentDto,
  ) {
    const organizationId = this.organizationService.getOrganizationIdFromUser(req.user);
    return this.organizationService.addConnectionCaseComment(
      req.user.id,
      organizationId,
      connectionId,
      caseId,
      dto,
    );
  }

  @Post('invitations/:invitationId/link')
  @UseGuards(JwtAuthGuard)
  @ApiOperation({ summary: 'Get a shareable invite link for a pending invitation' })
  getInvitationLink(
    @Req() req: { user: { id: string; organizationId?: string } },
    @Param('invitationId') invitationId: string,
  ) {
    const organizationId = this.organizationService.getOrganizationIdFromUser(req.user);
    return this.organizationService.getInvitationLink(req.user.id, organizationId, invitationId);
  }

  @Post('invite')
  @UseGuards(JwtAuthGuard)
  @ApiOperation({ summary: 'Create invite link for owner of not-yet-subscribed counterpart org' })
  inviteOrganization(
    @Req() req: { user: { id: string; organizationId?: string } },
    @Body() dto: InviteOrganizationDto,
  ) {
    const organizationId = this.organizationService.getOrganizationIdFromUser(req.user);
    return this.organizationService.inviteOrganization(req.user.id, organizationId, dto);
  }
}
