import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:injectable/injectable.dart';
import 'package:superport/core/constants/api_endpoints.dart';
import 'package:superport/core/errors/exceptions.dart';
import 'package:superport/data/datasources/remote/api_client.dart';
import 'package:superport/data/models/common/api_response.dart';
import 'package:superport/data/models/common/paginated_response.dart';
import 'package:superport/data/models/company/company_dto.dart';
import 'package:superport/data/models/company/company_list_dto.dart';
import 'package:superport/data/models/company/branch_dto.dart';
import 'package:superport/data/models/company/company_branch_flat_dto.dart';

abstract class CompanyRemoteDataSource {
  Future<PaginatedResponse<CompanyListDto>> getCompanies({
    int page = 1,
    int perPage = 20,
    String? search,
    bool? isActive,
  });
  
  Future<CompanyDto> createCompany(CompanyRequestDto request);
  
  Future<CompanyDto> getCompanyDetail(int id);
  
  Future<CompanyWithChildren> getCompanyWithChildren(int id);
  
  Future<CompanyDto> updateCompany(int id, CompanyUpdateRequestDto request);
  
  Future<void> deleteCompany(int id);
  
  Future<CompanyDto> restoreCompany(int id);
  
  Future<List<CompanyNameDto>> getCompanyNames();
  
  Future<List<CompanyWithChildren>> getCompaniesWithBranches();
  
  Future<bool> checkDuplicateCompany(String name);
  
  Future<List<CompanyListDto>> searchCompanies(String query);
  
  Future<void> updateCompanyStatus(int id, bool isActive);
  
  // Branch related methods
  Future<BranchResponse> createBranch(int companyId, CreateBranchRequest request);
  
  Future<BranchResponse> getBranchDetail(int companyId, int branchId);
  
  Future<BranchResponse> updateBranch(int companyId, int branchId, UpdateBranchRequest request);
  
  Future<void> deleteBranch(int companyId, int branchId);
  
  Future<List<BranchListDto>> getCompanyBranches(int companyId);
  
  Future<List<CompanyBranchFlatDto>> getCompanyBranchesFlat();
  
  // Headquarters methods
  Future<PaginatedResponse<CompanyListDto>> getHeadquartersWithPagination();
  Future<List<CompanyListDto>> getHeadquarters();
  Future<List<CompanyListDto>> getAllHeadquarters();
}

@LazySingleton(as: CompanyRemoteDataSource)
class CompanyRemoteDataSourceImpl implements CompanyRemoteDataSource {
  final ApiClient _apiClient;
  
  CompanyRemoteDataSourceImpl(this._apiClient);

  @override
  Future<PaginatedResponse<CompanyListDto>> getCompanies({
    int page = 1,
    int perPage = 20,
    String? search,
    bool? isActive,
  }) async {
    try {
      final queryParams = {
        'page': page,
        'per_page': perPage,
        if (search != null) 'search': search,
        if (isActive != null) 'is_active': isActive,
      };

      final response = await _apiClient.get(
        ApiEndpoints.companies,
        queryParameters: queryParams,
      );

      if (response.statusCode == 200) {
        // 백엔드 실제 응답 구조: {"data": [...], "total": 120, "page": 1, "page_size": 20, "total_pages": 6}
        final responseData = response.data;
        if (responseData != null && responseData['data'] != null) {
          final List<dynamic> dataList = responseData['data'];
          
          // CompanyListDto로 변환
          final items = dataList.map((item) => CompanyListDto.fromJson(item as Map<String, dynamic>)).toList();
          
          // PaginatedResponse 생성 (백엔드 실제 응답 구조 기준)
          return PaginatedResponse<CompanyListDto>(
            items: items,
            page: responseData['page'] ?? page,
            size: responseData['page_size'] ?? perPage,
            totalElements: responseData['total'] ?? 0,
            totalPages: responseData['total_pages'] ?? 1,
            first: (responseData['page'] ?? page) == 1,
            last: (responseData['page'] ?? page) >= (responseData['total_pages'] ?? 1),
          );
        } else {
          throw ApiException(
            message: 'Invalid response format',
            statusCode: response.statusCode,
          );
        }
      } else {
        throw ApiException(
          message: 'Failed to load companies',
          statusCode: response.statusCode,
        );
      }
    } catch (e) {
      if (e is ApiException) rethrow;
      throw ApiException(message: e.toString());
    }
  }

  @override
  Future<CompanyDto> createCompany(CompanyRequestDto request) async {
    try {
      debugPrint('[CompanyRemoteDataSource] Sending POST request to ${ApiEndpoints.companies}');
      debugPrint('[CompanyRemoteDataSource] Request data: ${request.toJson()}');
      
      final response = await _apiClient.post(
        ApiEndpoints.companies,
        data: request.toJson(),
      );

      debugPrint('[CompanyRemoteDataSource] Response status: ${response.statusCode}');
      debugPrint('[CompanyRemoteDataSource] Response data: ${response.data}');

      if (response.statusCode == 201 || response.statusCode == 200) {
        // 백엔드가 직접 CompanyDto 형식으로 응답하므로 바로 파싱
        debugPrint('[CompanyRemoteDataSource] Parsing response as CompanyDto');
        return CompanyDto.fromJson(response.data as Map<String, dynamic>);
      } else {
        throw ApiException(
          message: 'Failed to create company - Status: ${response.statusCode}',
          statusCode: response.statusCode,
        );
      }
    } catch (e, stackTrace) {
      debugPrint('[CompanyRemoteDataSource] Error creating company: $e');
      debugPrint('[CompanyRemoteDataSource] Stack trace: $stackTrace');
      if (e is ApiException) rethrow;
      throw ApiException(message: 'Error creating company: $e');
    }
  }

  @override
  Future<CompanyDto> getCompanyDetail(int id) async {
    try {
      final response = await _apiClient.dio.get(
        '${ApiEndpoints.companies}/$id',
      );

      return CompanyDto.fromJson(response.data);
    } on DioException catch (e) {
      throw ServerException(
        message: e.response?.data['message'] ?? 'Failed to fetch company detail',
        statusCode: e.response?.statusCode,
      );
    }
  }

  @override
  Future<CompanyWithChildren> getCompanyWithChildren(int id) async {
    try {
      final response = await _apiClient.dio.get(
        '${ApiEndpoints.companies}/$id/with-branches',
      );

      return CompanyWithChildren.fromJson(response.data['data']);
    } on DioException catch (e) {
      throw ServerException(
        message: e.response?.data['message'] ?? 'Failed to fetch company with branches',
        statusCode: e.response?.statusCode,
      );
    }
  }

  @override
  Future<CompanyDto> updateCompany(int id, CompanyUpdateRequestDto request) async {
    try {
      final response = await _apiClient.dio.put(
        '${ApiEndpoints.companies}/$id',
        data: request.toJson(),
      );

      return CompanyDto.fromJson(response.data);
    } on DioException catch (e) {
      throw ServerException(
        message: e.response?.data['message'] ?? 'Failed to update company',
        statusCode: e.response?.statusCode,
      );
    }
  }

  @override
  Future<void> deleteCompany(int id) async {
    try {
      await _apiClient.dio.delete(
        '${ApiEndpoints.companies}/$id',
      );
    } on DioException catch (e) {
      throw ServerException(
        message: e.response?.data['message'] ?? 'Failed to delete company',
        statusCode: e.response?.statusCode,
      );
    }
  }

  @override
  Future<CompanyDto> restoreCompany(int id) async {
    try {
      final response = await _apiClient.dio.put(
        '${ApiEndpoints.companies}/$id/restore',
      );

      return CompanyDto.fromJson(response.data['data']);
    } on DioException catch (e) {
      throw ServerException(
        message: e.response?.data['message'] ?? 'Failed to restore company',
        statusCode: e.response?.statusCode,
      );
    }
  }

  @override
  Future<List<CompanyNameDto>> getCompanyNames() async {
    try {
      final response = await _apiClient.dio.get(
        '${ApiEndpoints.companies}/names',
      );

      final List<dynamic> data = response.data['data'];
      return data.map((json) => CompanyNameDto.fromJson(json)).toList();
    } on DioException catch (e) {
      throw ServerException(
        message: e.response?.data['message'] ?? 'Failed to fetch company names',
        statusCode: e.response?.statusCode,
      );
    }
  }

  // Branch methods
  @override
  Future<BranchResponse> createBranch(int companyId, CreateBranchRequest request) async {
    try {
      final response = await _apiClient.dio.post(
        '${ApiEndpoints.companies}/$companyId/branches',
        data: request.toJson(),
      );

      return BranchResponse.fromJson(response.data['data']);
    } on DioException catch (e) {
      throw ServerException(
        message: e.response?.data['message'] ?? 'Failed to create branch',
        statusCode: e.response?.statusCode,
      );
    }
  }

  @override
  Future<BranchResponse> getBranchDetail(int companyId, int branchId) async {
    try {
      final response = await _apiClient.dio.get(
        '${ApiEndpoints.companies}/$companyId/branches/$branchId',
      );

      return BranchResponse.fromJson(response.data['data']);
    } on DioException catch (e) {
      throw ServerException(
        message: e.response?.data['message'] ?? 'Failed to fetch branch detail',
        statusCode: e.response?.statusCode,
      );
    }
  }

  @override
  Future<BranchResponse> updateBranch(int companyId, int branchId, UpdateBranchRequest request) async {
    try {
      final response = await _apiClient.dio.put(
        '${ApiEndpoints.companies}/$companyId/branches/$branchId',
        data: request.toJson(),
      );

      return BranchResponse.fromJson(response.data['data']);
    } on DioException catch (e) {
      throw ServerException(
        message: e.response?.data['message'] ?? 'Failed to update branch',
        statusCode: e.response?.statusCode,
      );
    }
  }

  @override
  Future<void> deleteBranch(int companyId, int branchId) async {
    try {
      await _apiClient.dio.delete(
        '${ApiEndpoints.companies}/$companyId/branches/$branchId',
      );
    } on DioException catch (e) {
      throw ServerException(
        message: e.response?.data['message'] ?? 'Failed to delete branch',
        statusCode: e.response?.statusCode,
      );
    }
  }

  @override
  Future<List<BranchListDto>> getCompanyBranches(int companyId) async {
    try {
      final response = await _apiClient.dio.get(
        '${ApiEndpoints.companies}/$companyId/branches',
      );

      final List<dynamic> data = response.data['data'];
      return data.map((json) => BranchListDto.fromJson(json)).toList();
    } on DioException catch (e) {
      throw ServerException(
        message: e.response?.data['message'] ?? 'Failed to fetch company branches',
        statusCode: e.response?.statusCode,
      );
    }
  }
  
  @override
  Future<List<CompanyWithChildren>> getCompaniesWithBranches() async {
    try {
      final response = await _apiClient.get('${ApiEndpoints.companies}/branches');
      
      if (response.statusCode == 200) {
        final apiResponse = ApiResponse<List<CompanyWithChildren>>.fromJson(
          response.data,
          (json) => (json as List)
              .map((item) => CompanyWithChildren.fromJson(item))
              .toList(),
        );
        return apiResponse.data!;
      } else {
        throw ApiException(
          message: 'Failed to load companies with branches',
          statusCode: response.statusCode,
        );
      }
    } catch (e) {
      if (e is ApiException) rethrow;
      throw ApiException(message: e.toString());
    }
  }
  
  @override
  Future<List<CompanyBranchFlatDto>> getCompanyBranchesFlat() async {
    try {
      final response = await _apiClient.get('${ApiEndpoints.companies}/branches');
      
      if (response.statusCode == 200) {
        final responseData = response.data;
        if (responseData != null && responseData['success'] == true && responseData['data'] != null) {
          final List<dynamic> dataList = responseData['data'];
          return dataList.map((item) => 
            CompanyBranchFlatDto.fromJson(item as Map<String, dynamic>)
          ).toList();
        } else {
          throw ApiException(
            message: responseData?['error']?['message'] ?? 'Failed to load company branches',
            statusCode: response.statusCode,
          );
        }
      } else {
        throw ApiException(
          message: 'Failed to load company branches',
          statusCode: response.statusCode,
        );
      }
    } catch (e) {
      if (e is ApiException) rethrow;
      throw ApiException(message: e.toString());
    }
  }
  
  @override
  Future<bool> checkDuplicateCompany(String name) async {
    try {
      final response = await _apiClient.get(
        '${ApiEndpoints.companies}/check-duplicate',
        queryParameters: {'name': name},
      );
      
      if (response.statusCode == 200) {
        final apiResponse = ApiResponse<Map<String, dynamic>>.fromJson(
          response.data,
          (json) => json as Map<String, dynamic>,
        );
        return apiResponse.data?['exists'] ?? false;
      } else {
        throw ApiException(
          message: 'Failed to check duplicate',
          statusCode: response.statusCode,
        );
      }
    } catch (e) {
      if (e is ApiException) rethrow;
      throw ApiException(message: e.toString());
    }
  }
  
  @override
  Future<List<CompanyListDto>> searchCompanies(String query) async {
    try {
      final response = await _apiClient.get(
        '${ApiEndpoints.companies}/search',
        queryParameters: {'q': query},
      );
      
      if (response.statusCode == 200) {
        final apiResponse = ApiResponse<List<CompanyListDto>>.fromJson(
          response.data,
          (json) => (json as List)
              .map((item) => CompanyListDto.fromJson(item))
              .toList(),
        );
        return apiResponse.data!;
      } else {
        throw ApiException(
          message: 'Failed to search companies',
          statusCode: response.statusCode,
        );
      }
    } catch (e) {
      if (e is ApiException) rethrow;
      throw ApiException(message: e.toString());
    }
  }
  
  @override
  Future<void> updateCompanyStatus(int id, bool isActive) async {
    try {
      final response = await _apiClient.patch(
        '${ApiEndpoints.companies}/$id/status',
        data: {'is_active': isActive},
      );
      
      if (response.statusCode != 200) {
        throw ApiException(
          message: 'Failed to update company status',
          statusCode: response.statusCode,
        );
      }
    } catch (e) {
      if (e is ApiException) rethrow;
      throw ApiException(message: e.toString());
    }
  }
  
  @override
  Future<PaginatedResponse<CompanyListDto>> getHeadquartersWithPagination() async {
    try {
      // /headquarters 엔드포인트가 백엔드에 없으므로 /companies API에서 본사만 필터링
      final response = await _apiClient.get(
        ApiEndpoints.companies,
        queryParameters: {
          'page': 1,
          'per_page': 1000, // 충분히 큰 값으로 모든 본사 조회
          'is_active': true,
        },
      );
      
      if (response.statusCode == 200) {
        final responseData = response.data;
        if (responseData != null && responseData['data'] != null) {
          final List<dynamic> dataList = responseData['data'];
          
          // parentCompanyId가 null인 본사만 필터링
          final headquartersData = dataList.where((item) => item['parent_company_id'] == null).toList();
          
          // CompanyListDto로 변환
          final items = headquartersData.map((item) => 
            CompanyListDto.fromJson(item as Map<String, dynamic>)
          ).toList();
          
          // PaginatedResponse 생성
          return PaginatedResponse<CompanyListDto>(
            items: items,
            page: 1,
            size: items.length,
            totalElements: items.length, // 본사 개수
            totalPages: 1,
            first: true,
            last: true,
          );
        } else {
          throw ApiException(
            message: 'Invalid response format',
            statusCode: response.statusCode,
          );
        }
      } else {
        throw ApiException(
          message: 'Failed to load headquarters',
          statusCode: response.statusCode,
        );
      }
    } catch (e) {
      if (e is ApiException) rethrow;
      throw ApiException(message: e.toString());
    }
  }

  @override
  Future<List<CompanyListDto>> getHeadquarters() async {
    try {
      // /headquarters 엔드포인트가 백엔드에 없으므로 /companies API에서 본사만 필터링
      final response = await _apiClient.get(
        ApiEndpoints.companies,
        queryParameters: {
          'page': 1,
          'per_page': 1000, // 충분히 큰 값으로 모든 본사 조회
          'is_active': true,
        },
      );
      
      if (response.statusCode == 200) {
        final responseData = response.data;
        if (responseData != null && responseData['data'] != null) {
          final List<dynamic> dataList = responseData['data'];
          
          // parentCompanyId가 null인 본사만 필터링
          final headquartersData = dataList.where((item) => item['parent_company_id'] == null).toList();
          
          return headquartersData.map((item) => 
            CompanyListDto.fromJson(item as Map<String, dynamic>)
          ).toList();
        } else {
          throw ApiException(
            message: 'Invalid response format',
            statusCode: response.statusCode,
          );
        }
      } else {
        throw ApiException(
          message: 'Failed to load headquarters',
          statusCode: response.statusCode,
        );
      }
    } catch (e) {
      if (e is ApiException) rethrow;
      throw ApiException(message: e.toString());
    }
  }

  @override
  Future<List<CompanyListDto>> getAllHeadquarters() async {
    try {
      // /headquarters 엔드포인트가 백엔드에 없으므로 /companies API에서 본사만 필터링
      final response = await _apiClient.get(
        ApiEndpoints.companies,
        queryParameters: {
          'per_page': 1000,  // Large enough to get all headquarters
          'page': 1,
          'is_active': true,
        },
      );
      
      if (response.statusCode == 200) {
        final responseData = response.data;
        if (responseData != null && responseData['data'] != null) {
          final List<dynamic> dataList = responseData['data'];
          
          // parentCompanyId가 null인 본사만 필터링
          final headquartersData = dataList.where((item) => item['parent_company_id'] == null).toList();
          
          return headquartersData.map((item) => 
            CompanyListDto.fromJson(item as Map<String, dynamic>)
          ).toList();
        } else {
          throw ApiException(
            message: 'Invalid response format',
            statusCode: response.statusCode,
          );
        }
      } else {
        throw ApiException(
          message: 'Failed to load all headquarters',
          statusCode: response.statusCode,
        );
      }
    } catch (e) {
      if (e is ApiException) rethrow;
      throw ApiException(message: e.toString());
    }
  }
}