package com.social.media.interfaces.web.controller;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.social.media.application.company.command.CreateCompanyCommand;
import com.social.media.application.company.command.UpdateCompanyCommand;
import com.social.media.application.company.dto.CompanyResponseDto;
import com.social.media.application.company.handler.CreateCompanyCommandHandler;
import com.social.media.application.company.handler.UpdateCompanyCommandHandler;
import com.social.media.domain.company.aggregate.Company;
import com.social.media.domain.company.valueobject.CompanyId;
import com.social.media.domain.user.valueobject.UserId;
import com.social.media.infrastructure.persistence.company.query.CompanyQueryServiceImpl;
import com.social.media.interfaces.web.dto.company.CompanyResponse;
import com.social.media.interfaces.web.dto.company.CreateCompanyRequest;
import com.social.media.interfaces.web.dto.company.UpdateCompanyRequest;
import com.social.media.interfaces.web.mapper.CompanyDtoMapper;

import jakarta.validation.Valid;

/**
 * REST Controller for Company management - REFACTORED VERSION
 * All operations now include security validation with userId
 */
@RestController
@RequestMapping("/api/v1/companies")

public class CompanyController {
    
    private final CreateCompanyCommandHandler createCompanyHandler;
    private final UpdateCompanyCommandHandler updateCompanyHandler;
    private final CompanyQueryServiceImpl companyQueryService;
    private final CompanyDtoMapper companyDtoMapper;
    
    public CompanyController(CreateCompanyCommandHandler createCompanyHandler,
                           UpdateCompanyCommandHandler updateCompanyHandler,
                           CompanyQueryServiceImpl companyQueryService,
                           CompanyDtoMapper companyDtoMapper) {
        this.createCompanyHandler = createCompanyHandler;
        this.updateCompanyHandler = updateCompanyHandler;
        this.companyQueryService = companyQueryService;
        this.companyDtoMapper = companyDtoMapper;
    }
    
    /**
     * Create a new company
     */
    @PostMapping
    public ResponseEntity<CompanyResponseDto> createCompany(@Valid @RequestBody CreateCompanyRequest request) {
        CreateCompanyCommand command = companyDtoMapper.toCreateCommand(request);
        CompanyResponseDto response = createCompanyHandler.handle(command);
        return ResponseEntity.status(HttpStatus.CREATED).body(response);
    }
    
    /**
     * Get company by ID with security validation
     */
    @GetMapping("/{id}")
    public ResponseEntity<CompanyResponse> getCompany(@PathVariable String id) {
        var authInfo = getAuthenticatedUserInfo();
        CompanyId companyId = CompanyId.of(Long.valueOf(id));
        Company company = companyQueryService.findByIdWithSecurity(companyId, authInfo.getUserIdAsLong())
            .orElseThrow(() -> new RuntimeException("Company not found or access denied"));
        CompanyResponse response = companyDtoMapper.toResponse(company);
        return ResponseEntity.ok(response);
    }
    
    /**
     * Get current user's company
     */
    @GetMapping("/my-company")
    public ResponseEntity<CompanyResponse> getMyCompany() {
        var authInfo = getAuthenticatedUserInfo();
        Company company = companyQueryService.findOwnCompany(authInfo.getUserIdAsLong())
            .orElseThrow(() -> new RuntimeException("Company not found"));
        CompanyResponse response = companyDtoMapper.toResponse(company);
        return ResponseEntity.ok(response);
    }
    
    /**
     * Get all companies with pagination (Super Admin only)
     */
    @GetMapping
    public ResponseEntity<Page<CompanyResponse>> getAllCompanies(Pageable pageable) {
        var authInfo = getAuthenticatedUserInfo();
        Page<Company> companies = companyQueryService.findAllBySuperAdmin(authInfo.userId().value(), pageable);
        Page<CompanyResponse> response = companies.map(companyDtoMapper::toResponse);
        return ResponseEntity.ok(response);
    }
    
    /**
     * Update company
     */
    @PutMapping("/{id}")
    public ResponseEntity<CompanyResponseDto> updateCompany(
            @PathVariable String id,
            @Valid @RequestBody UpdateCompanyRequest request) {
        var authInfo = getAuthenticatedUserInfo();
        CompanyId companyId = CompanyId.of(Long.valueOf(id));
        
        // Verify user has access to this company
        companyQueryService.findByIdWithSecurity(companyId, authInfo.userId().value())
            .orElseThrow(() -> new RuntimeException("Company not found or access denied"));
        
        UpdateCompanyCommand command = companyDtoMapper.toUpdateCommand(companyId, request);
        CompanyResponseDto response = updateCompanyHandler.handle(command);
        return ResponseEntity.ok(response);
    }
    
    /**
     * Delete company (soft delete)
     */
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteCompany(@PathVariable String id) {
        var authInfo = getAuthenticatedUserInfo();
        CompanyId companyId = CompanyId.of(Long.valueOf(id));
        
        // Verify user has access to this company
        companyQueryService.findByIdWithSecurity(companyId, authInfo.userId().value())
            .orElseThrow(() -> new RuntimeException("Company not found or access denied"));
        
        // TODO: Implement delete command handler
        return ResponseEntity.noContent().build();
    }
    
    /**
     * Search companies by name (Super Admin only)
     */
    @GetMapping("/search")
    public ResponseEntity<Page<CompanyResponse>> searchCompanies(
            @RequestParam String name,
            Pageable pageable) {
        var authInfo = getAuthenticatedUserInfo();
        Page<Company> companies = companyQueryService.searchByNameAndSuperAdmin(name, authInfo.userId().value(), pageable);
        Page<CompanyResponse> response = companies.map(companyDtoMapper::toResponse);
        return ResponseEntity.ok(response);
    }
    
    /**
     * Get companies by status (Super Admin only)
     */
    @GetMapping("/status/{status}")
    public ResponseEntity<Page<CompanyResponse>> getCompaniesByStatus(
            @PathVariable String status,
            Pageable pageable) {
        var authInfo = getAuthenticatedUserInfo();
        Page<Company> companies = companyQueryService.findByStatusAndSuperAdmin(status, authInfo.userId().value(), pageable);
        Page<CompanyResponse> response = companies.map(companyDtoMapper::toResponse);
        return ResponseEntity.ok(response);
    }
    
    /**
     * Get companies by plan (Super Admin only)
     */
    @GetMapping("/plan/{plan}")
    public ResponseEntity<Page<CompanyResponse>> getCompaniesByPlan(
            @PathVariable String plan,
            Pageable pageable) {
        var authInfo = getAuthenticatedUserInfo();
        Page<Company> companies = companyQueryService.findByPlanAndSuperAdmin(plan, authInfo.userId().value(), pageable);
        Page<CompanyResponse> response = companies.map(companyDtoMapper::toResponse);
        return ResponseEntity.ok(response);
    }
    
    /**
     * Check if email exists
     */
    @GetMapping("/check-email")
    public ResponseEntity<Boolean> checkEmailExists(@RequestParam String email) {
        boolean exists = companyQueryService.existsByEmail(email);
        return ResponseEntity.ok(exists);
    }
    
    /**
     * Validate user belongs to company
     */
    @GetMapping("/{companyId}/validate-user")
    public ResponseEntity<Boolean> validateUserBelongsToCompany(@PathVariable Long companyId) {
        var authInfo = getAuthenticatedUserInfo();
        boolean belongs = companyQueryService.userBelongsToCompany(authInfo.userId().value(), companyId);
        return ResponseEntity.ok(belongs);
    }
    
    /**
     * Helper method to get authenticated user information
     */
    private AuthenticatedUserInfo getAuthenticatedUserInfo() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        
        // TODO: Implement proper authentication extraction based on your security setup
        // This is a temporary implementation - replace with actual JWT/session parsing
        
        if (authentication == null || !authentication.isAuthenticated()) {
            throw new RuntimeException("User not authenticated");
        }
        
        // Extract user ID and company ID from authentication
        // This will depend on your security implementation
        Long userId = extractUserIdFromAuthentication(authentication);
        Long companyId = extractCompanyIdFromAuthentication(authentication);
        
        return new AuthenticatedUserInfo(UserId.of(userId), companyId);
    }
    
    private Long extractUserIdFromAuthentication(Authentication authentication) {
        // TODO: Implement based on your JWT/session structure
        // For now, returning a default value - this needs proper implementation
        return 1L; // Temporary
    }
    
    private Long extractCompanyIdFromAuthentication(Authentication authentication) {
        // TODO: Implement based on your JWT/session structure
        // For now, returning a default value - this needs proper implementation
        return 1L; // Temporary
    }
    
    /**
     * Record to hold authenticated user information
     */
    private record AuthenticatedUserInfo(UserId userId, Long companyId) {
        public Long getUserIdAsLong() {
            // The valueobject UserId has a value() method that returns Long
            return userId.value();
        }
    }
}
