import { Injectable } from '@angular/core';
import axios from 'axios';
import { LoggerService } from './logger.service';

import { BASE_URL } from '../config/api.config';

function authHeaders() {
  const token = localStorage.getItem('jwtToken');
  return { Authorization: `Bearer ${token}` };
}

export interface UserUpdateRequest {
  firstName?: string;
  lastName?: string;
  phoneNumber?: string;
}

export interface UserInfo {
  id: string;
  email: string;
  firstName: string;
  lastName: string;
  phoneNumber?: string;
  role: 'ADMIN' | 'DOCTOR' | 'PATIENT';
  isActive: boolean;
  avatarUrl?: string;
  status?: 'ONLINE' | 'OFFLINE' | 'BUSY';
  isOnline?: boolean;
}

export interface DoctorProfile {
  id: string;
  firstName: string;
  lastName: string;
  phoneNumber: string;
  email?: string;
  medicalLicenseNumber?: string;
  specialization: string;
  yearsOfExperience: number;
  biography?: string;
  consultationFee?: number;
  defaultDurationMinutes?: number;
  isVerified?: boolean;
  avatarUrl?: string;
  // Enterprise fields
  streetAddress?: string;
  city?: string;
  state?: string;
  zipCode?: string;
  country?: string;
  educationDegree?: string;
  educationUniversity?: string;
  educationGraduationYear?: number;
  certifications?: string[];
  languagesSpoken?: string[];
  hospitalAffiliations?: string[];
  insuranceAccepted?: string[];
  professionalMemberships?: string[];
}

export interface DoctorUpdateRequest {
  medicalLicenseNumber?: string;
  specialization?: string;
  yearsOfExperience?: number;
  biography?: string;
  consultationFee?: number;
  defaultDurationMinutes?: number;
  // Enterprise fields
  streetAddress?: string;
  city?: string;
  state?: string;
  zipCode?: string;
  country?: string;
  educationDegree?: string;
  educationUniversity?: string;
  educationGraduationYear?: number;
  certifications?: string[];
  languagesSpoken?: string[];
  hospitalAffiliations?: string[];
  insuranceAccepted?: string[];
  professionalMemberships?: string[];
}

export interface PatientProfile {
  id: string;
  userId?: string;
  firstName: string;
  lastName: string;
  phoneNumber: string;
  email?: string;
  bloodType?: string;
  emergencyContactName?: string;
  emergencyContactPhone?: string;
  allergies?: string[];
  avatarUrl?: string;
  // Enterprise fields
  dateOfBirth?: string;
  gender?: string;
  streetAddress?: string;
  city?: string;
  state?: string;
  zipCode?: string;
  country?: string;
  insuranceProvider?: string;
  insurancePolicyNumber?: string;
  medicalHistorySummary?: string;
  currentMedications?: string[];
  primaryCarePhysicianName?: string;
  primaryCarePhysicianPhone?: string;
  preferredLanguage?: string;
  occupation?: string;
  maritalStatus?: string;
}

export interface PatientUpdateRequest {
  emergencyContactName?: string;
  emergencyContactPhone?: string;
  bloodType?: string;
  allergies?: string[];
  // Enterprise fields
  dateOfBirth?: string;
  gender?: string;
  streetAddress?: string;
  city?: string;
  state?: string;
  zipCode?: string;
  country?: string;
  insuranceProvider?: string;
  insurancePolicyNumber?: string;
  medicalHistorySummary?: string;
  currentMedications?: string[];
  primaryCarePhysicianName?: string;
  primaryCarePhysicianPhone?: string;
  preferredLanguage?: string;
  occupation?: string;
  maritalStatus?: string;
}

@Injectable({ providedIn: 'root' })
export class UserService {
  private currentUserCache: UserInfo | null = null;
  private currentUserPromise: Promise<UserInfo | null> | null = null;
  private cacheTimestamp: number = 0;
  private readonly CACHE_DURATION = 60000; // 60 seconds

  constructor(private logger: LoggerService) {}

  getUserEmail(): string | null {
    const token = localStorage.getItem('jwtToken');
    if (!token) return null;
    
    try {
      // Decode JWT token (simple base64 decode)
      const payload = JSON.parse(atob(token.split('.')[1]));
      return payload.sub || payload.email || null;
    } catch (e) {
      return null;
    }
  }

  async getCurrentUser(): Promise<UserInfo | null> {
    // Use the proper endpoint that works for all authenticated users
    return await this.getCurrentUserProfile();
  }

  async getDoctorIdByUserId(userId: string): Promise<string | null> {
    try {
      // First, check if current user is a doctor and use the /me endpoint
      const currentUser = await this.getCurrentUserProfile();
      if (currentUser?.role === 'DOCTOR' && currentUser.id === userId) {
        const doctorProfile = await this.getDoctorProfile();
        if (doctorProfile?.id) {
          return doctorProfile.id;
        }
      }
      
      // If not current user or not a doctor, try admin endpoint (only works for admins)
      const currentUserForCheck = currentUser || await this.getCurrentUserProfile();
      if (currentUserForCheck?.role === 'ADMIN') {
        const doctors = await axios.get(`${BASE_URL}/api/v3/admin/doctors`, { headers: authHeaders() });
        const doctor = doctors.data.find((d: any) => d.user?.id === userId);
        return doctor?.id || null;
      }
      
      return null;
    } catch (e: any) {
      // Silently handle 403 errors (expected for non-admin users)
      if (e?.response?.status === 403) {
        return null;
      }
      // Only log unexpected errors
      this.logger.warn('Error getting doctor ID:', e);
      return null;
    }
  }

  async getPatientIdByUserId(userId: string): Promise<string | null> {
    try {
      // First, check if current user is a patient and use the /me endpoint
      const currentUser = await this.getCurrentUserProfile();
      if (currentUser?.role === 'PATIENT' && currentUser.id === userId) {
        const patientProfile = await this.getPatientProfile();
        if (patientProfile?.id) {
          return patientProfile.id;
        }
      }
      
      // If not current user or not a patient, try admin endpoint (only works for admins)
      const currentUserForCheck = currentUser || await this.getCurrentUserProfile();
      if (currentUserForCheck?.role === 'ADMIN') {
        const patients = await axios.get(`${BASE_URL}/api/v3/admin/patients`, { headers: authHeaders() });
        const patient = patients.data.find((p: any) => p.user?.id === userId);
        return patient?.id || null;
      }
      
      return null;
    } catch (e: any) {
      // Silently handle 403 errors (expected for non-admin users)
      if (e?.response?.status === 403) {
        return null;
      }
      this.logger.warn('Error getting patient ID:', e);
      return null;
    }
  }

  async getUserById(userId: string): Promise<UserInfo | null> {
    try {
      // Check if current user is admin before calling admin endpoint
      const currentUser = await this.getCurrentUserProfile();
      if (currentUser?.role !== 'ADMIN') {
        // Non-admin users can't access this endpoint
        return null;
      }
      
      const res = await axios.get(`${BASE_URL}/api/v3/admin/users`, { headers: authHeaders() });
      const users = res.data;
      return users.find((u: UserInfo) => u.id === userId) || null;
    } catch (e: any) {
      // Silently handle 403 errors (expected for non-admin users)
      if (e?.response?.status === 403) {
        return null;
      }
      this.logger.warn('Error getting user by ID:', e);
      return null;
    }
  }

  async getCurrentUserProfile(): Promise<UserInfo | null> {
    // Check cache validity
    const now = Date.now();
    if (this.currentUserCache && (now - this.cacheTimestamp) < this.CACHE_DURATION) {
      return this.currentUserCache;
    }

    // If there's already a pending request, return that promise instead of making a new one
    if (this.currentUserPromise) {
      return this.currentUserPromise;
    }

    // Create a new request promise
    this.currentUserPromise = (async () => {
      try {
        const res = await axios.get(`${BASE_URL}/api/v3/users/me`, { 
          headers: authHeaders(),
          timeout: 10000 // 10 second timeout
        });
        const user = res.data;
        // Update cache
        this.currentUserCache = user;
        this.cacheTimestamp = Date.now();
        this.currentUserPromise = null; // Clear the promise after completion
        return user;
      } catch (e: any) {
        this.currentUserPromise = null; // Clear the promise on error
        // Only log non-aborted errors to reduce noise
        if (e.code !== 'ECONNABORTED' && e.code !== 'ERR_CANCELED') {
          this.logger.error('Failed to get current user profile:', e);
        }
        return null;
      }
    })();

    return this.currentUserPromise;
  }

  // Method to clear cache (useful after login/logout or profile updates)
  clearUserCache(): void {
    this.currentUserCache = null;
    this.currentUserPromise = null;
    this.cacheTimestamp = 0;
  }

  async updateUserProfile(updateData: UserUpdateRequest): Promise<UserInfo> {
    const res = await axios.patch(`${BASE_URL}/api/v3/users/me`, updateData, { headers: authHeaders() });
    // Clear cache after update to force refresh
    this.clearUserCache();
    this.currentUserCache = res.data;
    this.cacheTimestamp = Date.now();
    return res.data;
  }

  async changePassword(currentPassword: string, newPassword: string, confirmNewPassword: string): Promise<void> {
    try {
      await axios.post(`${BASE_URL}/api/v3/users/me/change-password`, {
        currentPassword,
        newPassword,
        confirmNewPassword
      }, { headers: authHeaders() });
    } catch (error: any) {
      if (error?.response?.status === 400 && error?.response?.data?.message) {
        throw new Error(error.response.data.message);
      }
      if (error?.response?.status === 401) {
        throw new Error('Current password is incorrect');
      }
      throw error;
    }
  }

  async getDoctorProfile(): Promise<DoctorProfile | null> {
    try {
      const res = await axios.get(`${BASE_URL}/api/v3/users/doctors/me`, { headers: authHeaders() });
      return res.data;
    } catch (e: any) {
      this.logger.error('Failed to get doctor profile:', e);
      return null;
    }
  }

  async updateDoctorProfile(updateData: DoctorUpdateRequest): Promise<DoctorProfile> {
    const res = await axios.patch(`${BASE_URL}/api/v3/users/doctors/me`, updateData, { headers: authHeaders() });
    return res.data;
  }

  async getPatientProfile(): Promise<PatientProfile | null> {
    try {
      const res = await axios.get(`${BASE_URL}/api/v3/users/patients/me`, { headers: authHeaders() });
      return res.data;
    } catch (e: any) {
      this.logger.error('Failed to get patient profile:', e);
      return null;
    }
  }

  async updatePatientProfile(updateData: PatientUpdateRequest): Promise<PatientProfile> {
    const res = await axios.patch(`${BASE_URL}/api/v3/users/patients/me`, updateData, { headers: authHeaders() });
    return res.data;
  }

  async getAllDoctors(): Promise<DoctorProfile[]> {
    try {
      const res = await axios.get(`${BASE_URL}/api/v3/users/doctors`, { headers: authHeaders() });
      return res.data;
    } catch (e: any) {
      this.logger.error('Failed to get all doctors:', e);
      return [];
    }
  }

  async getAllPatients(): Promise<PatientProfile[]> {
    try {
      const res = await axios.get(`${BASE_URL}/api/v3/users/patients`, { headers: authHeaders() });
      return res.data;
    } catch (e: any) {
      this.logger.error('Failed to get all patients:', e);
      return [];
    }
  }

  async getDoctorProfileById(doctorId: string): Promise<DoctorProfile> {
    try {
      const res = await axios.get(`${BASE_URL}/api/v3/users/doctors/${doctorId}`, { headers: authHeaders() });
      return res.data;
    } catch (e: any) {
      if (e?.response?.status === 403) {
        throw new Error('Access denied: Unable to view doctor profile');
      }
      if (e?.response?.status === 404) {
        throw new Error('Doctor not found');
      }
      throw e;
    }
  }

  async getPatientProfileById(patientId: string): Promise<PatientProfile> {
    try {
      const res = await axios.get(`${BASE_URL}/api/v3/users/patients/${patientId}`, { headers: authHeaders() });
      return res.data;
    } catch (e: any) {
      if (e?.response?.status === 403) {
        throw new Error('Access denied: Only doctors can view patient profiles');
      }
      if (e?.response?.status === 404) {
        throw new Error('Patient not found');
      }
      throw e;
    }
  }

  async uploadAvatar(file: File): Promise<string> {
    const formData = new FormData();
    formData.append('file', file);
    const res = await axios.post(`${BASE_URL}/api/v3/files/avatar`, formData, {
      headers: {
        ...authHeaders(),
        'Content-Type': 'multipart/form-data'
      }
    });
    return res.data.avatarUrl;
  }

  async uploadAvatarBase64(base64Image: string): Promise<string> {
    const res = await axios.post(
      `${BASE_URL}/api/v3/files/avatar/base64`,
      { image: base64Image },
      { headers: authHeaders() }
    );
    return res.data.avatarUrl;
  }

  async deleteAvatar(): Promise<void> {
    await axios.delete(`${BASE_URL}/api/v3/files/avatar`, { headers: authHeaders() });
  }

  getAvatarUrl(avatarUrl?: string): string {
    if (!avatarUrl) return '';
    // If already a full URL, return as-is
    if (avatarUrl.startsWith('http://') || avatarUrl.startsWith('https://')) {
      return avatarUrl;
    }
    // If it starts with /, prepend BASE_URL
    if (avatarUrl.startsWith('/')) {
      // Fix: Ensure avatar URLs use /api/v3/files/avatars/ instead of /api/files/avatars/ or /files/avatars/
      if (avatarUrl.startsWith('/api/files/avatars/')) {
        // Replace /api/files/avatars/ with /api/v3/files/avatars/
        return `${BASE_URL}/api/v3/files/avatars/${avatarUrl.substring('/api/files/avatars/'.length)}`;
      } else if (avatarUrl.startsWith('/files/avatars/')) {
        return `${BASE_URL}/api/v3${avatarUrl}`;
      }
      return `${BASE_URL}${avatarUrl}`;
    }
    // Otherwise, assume it's a relative path and prepend BASE_URL with /
    // Fix: Ensure avatar URLs use /api/v3/files/avatars/ instead of /api/files/avatars/ or /files/avatars/
    if (avatarUrl.startsWith('api/files/avatars/')) {
      // Replace api/files/avatars/ with api/v1/files/avatars/
      return `${BASE_URL}/api/v3/files/avatars/${avatarUrl.substring('api/files/avatars/'.length)}`;
    } else if (avatarUrl.startsWith('files/avatars/')) {
      return `${BASE_URL}/api/v3/${avatarUrl}`;
    }
    return `${BASE_URL}/${avatarUrl}`;
  }
}

