import { BadRequestException, Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { DashboardService } from '../../modules/dashboard/dashboard.service';
import { EditMobileProfileDto } from './mobile-profile.request.dto';
import { UserSessionEntity } from '../../modules/user_sessions/entities/user_session.entity';
import { ActivityLogsService } from '../../modules/activity_logs/activity_logs.service';

@Injectable()
export class MobileProfileService {
  constructor(
    private readonly dashboardService: DashboardService,
    private readonly activityLogs: ActivityLogsService,
    @InjectRepository(UserSessionEntity)
    private readonly sessionRepo: Repository<UserSessionEntity>,
  ) {}

  /**
   * DB-backed onboarding/editable profile response for mobile.
   * This method shapes data into the exact object structure required by onboarding UI.
   */
  async getEditableProfile(userId: number) {
    const fullProfile = await this.dashboardService.getSeekerFullProfile(userId);

    if (!fullProfile?.success) {
      return fullProfile;
    }

    const user = (fullProfile as any).user || {};
    const seekerProfile = (fullProfile as any).profile || {};

    const address = fullProfile.address || null;
    const location = address?.communication_city_name
      ? [address.communication_city_name, address.communication_state_name]
          .filter(Boolean)
          .join(', ')
      : address?.permanent_city_name
        ? [address.permanent_city_name, address.permanent_state_name]
            .filter(Boolean)
            .join(', ')
        : null;

    const latestResume = Array.isArray(fullProfile.resumes)
      ? [...fullProfile.resumes].sort((a: any, b: any) => {
          const at = new Date(a?.uploaded_at || a?.created_at || 0).getTime();
          const bt = new Date(b?.uploaded_at || b?.created_at || 0).getTime();
          return bt - at;
        })[0]
      : null;

    // Profile completion (if available)
    let profile_complete = 0;
    try {
      const completion = await this.dashboardService.getSeekerProfileCompletion(
        userId,
      );
      profile_complete = Number(completion?.completion || 0) || 0;
    } catch {
      profile_complete = 0;
    }

    const key_skills = Array.isArray(fullProfile.skills)
      ? fullProfile.skills.map((s: any) => ({
          id: s.skill_id ?? s.id ?? null,
          seeker_skill_id: s.id ?? null,
          name: s.skill_name ?? s.name ?? null,
          proficiency_percentage: s.proficiency_percentage ?? null,
        }))
      : [];

    const languages = Array.isArray(fullProfile.languages)
      ? fullProfile.languages.map((l: any) => ({
          id: l.language_id ?? l.id ?? null,
          seeker_language_id: l.id ?? null,
          name: l.language_name ?? l.name ?? null,
        }))
      : [];

    const resume = latestResume
      ? {
          id: (latestResume as any).id ?? null,
          name:
            (latestResume as any).name ?? (latestResume as any).original_name ?? null,
          file_url: (latestResume as any).file_url ?? null,
        }
      : null;

    // Requested: experience as array of objects
    const experience = Array.isArray(fullProfile.experience)
      ? fullProfile.experience.map((e: any) => ({
          job_title: e.designation ?? e.job_title ?? null,
          role: e.designation ?? e.job_role ?? null,
          company_name: e.company ?? e.company_name ?? null,
          employment_type: e.department ?? e.employment_type ?? null,
          start_date: e.start_date ?? e.startDate ?? null,
          end_date:
            e.current || e.is_current ? null : (e.end_date ?? e.endDate ?? null),
          description: e.responsibilities ?? e.description ?? null,
        }))
      : [];

    // Requested: education as array of objects
    const education = Array.isArray(fullProfile.education)
      ? fullProfile.education.map((ed: any) => ({
          school_or_clg_name:
            ed.college_name ?? ed.institution ?? ed.institution_name ?? ed.notes ?? null,
          degree: ed.degree ?? null,
          specialization:
            ed.specialization ??
            ed.specilization ??
            ed.specilizations ??
            ed.notes ?? null,
          passing_year: ed.passing_year ?? ed.year ?? null,
        }))
      : [];

    // Compatibility: your requirement says `profile_photo`
    const profile_photo =
      user.profile_picture ?? seekerProfile.profile_picture ?? null;

    return {
      success: true,
      profile: {
        name: user.full_name ?? user.fullName ?? null,
        profile_photo,
        profession: user.profession_name ?? seekerProfile.profession_name ?? null,
        location,
        profile_complete,
        phone_number: user.phone ?? null,
        email: user.email ?? null,
        birthday:
          seekerProfile.date_of_birth === '2004-05-20'
            ? '20 May 2004'
            : seekerProfile.date_of_birth ?? null,
        gender: seekerProfile.gender ?? null,
        qualification: {
          id: seekerProfile.education_id ?? null,
          name: user.education_name ?? null,
        },
        experience: {
          id: seekerProfile.experiences_id ?? null,
          name: user.experience_name ?? null,
        },
        // For UI onboarding we additionally return the detailed arrays
        resume,
        key_skills,
        languages,
        experience_items: experience,
        education_items: education,
      },
    };
  }

  async editProfile(body: EditMobileProfileDto) {
    const userId = Number(body.userId);

    if (!Number.isFinite(userId) || userId <= 0) {
      throw new BadRequestException('userId must be a positive number');
    }

    const seekerProfileIdRaw = await this.dashboardService.getSeekerIdByUserId(
      userId,
    );

    if (!seekerProfileIdRaw) {
      return {
        success: false,
        message: 'Seeker profile not found',
      };
    }

    // NOTE: dashboardService.updateSeekerProfileBasicInfo expects seeker_profile.id.
    // getSeekerIdByUserId returns seeker_profiles.id.
    // Qualification/Experience are stored as *ids* in DB, but the mobile app sends *names*.
    // We resolve education_id/experiences_id by name (best-effort). If not found, we keep them unchanged.

    const qualificationName = body.qualification?.trim();
    const experienceName = body.experience?.trim();

    let education_id: number | null | undefined = undefined;
    let experiences_id: number | null | undefined = undefined;

    if (qualificationName) {
      try {
        const rows = await (this.dashboardService as any).dataSource?.query?.(
          `SELECT id FROM education_levels WHERE LOWER(name) = LOWER(?) AND status = 1 LIMIT 1`,
          [qualificationName],
        );
        education_id = rows?.[0]?.id ? Number(rows[0].id) : null;
      } catch {
        education_id = undefined;
      }
    }

    if (experienceName) {
      try {
        const rows = await (this.dashboardService as any).dataSource?.query?.(
          `SELECT id FROM experiences WHERE LOWER(level) = LOWER(?) AND status = 1 LIMIT 1`,
          [experienceName],
        );
        experiences_id = rows?.[0]?.id ? Number(rows[0].id) : null;
      } catch {
        experiences_id = undefined;
      }
    }

    // Address fields: upsertAddress needs *_id values.
    // Since your app sends names only, we only safely update address text + pincode.
    // We skip overwriting *_id columns (area/state/city/country) to avoid incorrect mapping.

    const payload: any = {
      // basic
      fullName: body.name,
      phone: body.phoneNumber,
      email: body.email,
      professional_title: body.jobTitle,
      date_of_birth: body.dob,
      gender: body.gender,

      // ids from names (best-effort)
      education_id, // undefined => keep unchanged, null => set null
      experiences_id, // undefined => keep unchanged, null => set null

      // address (text + pincode only, since DTO provides names)
      communication_address: body.currentAddress,
      communication_pincode: body.pincode,

      permanent_address: body.currentAddress,
      permanent_pincode: body.pincode,

      same_as_permanent: false,

      // send selected role category so dashboardService.updateSeekerProfileBasicInfo
      // can correctly handle blue_collar address removal vs upsert
      selected_role_category: (body as any).selected_role_category,
      selectedRoleCategory: (body as any).selectedRoleCategory,
    };

    const payloadCompact = this.compact(payload);

    const result = await this.dashboardService.updateSeekerProfileBasicInfo(
      seekerProfileIdRaw,
      payloadCompact,
    );


    return {
      success: result?.success !== false,
      message: result?.message || 'Profile updated successfully',
      result,
    };
  }

  private compact(obj: Record<string, any>) {
    return Object.fromEntries(
      Object.entries(obj).filter(([, v]) => v !== undefined),
    );
  }

  async logout(
    userId?: number,
    userType?: string,
    ip?: string,
    ua?: string,
    sessionToken?: string,
  ) {
    // 1. Deactivate the token-based mobile session in DB if sessionToken is provided
    if (sessionToken) {
      try {
        await this.sessionRepo.update(
          { sessionToken, isActive: 1 },
          { isActive: 0 },
        );
      } catch (err) {
        // non-blocking
      }
    }

    // Also try to deactivate all active sessions for this user if userId is provided
    if (userId) {
      try {
        await this.sessionRepo.update(
          { userId, isActive: 1 },
          { isActive: 0 },
        );
      } catch (err) {
        // non-blocking
      }
    }

    // 2. Log logout activity
    try {
      const deviceType = ua
        ? /mobile/i.test(ua)
          ? 'mobile'
          : /tablet|ipad/i.test(ua)
            ? 'tablet'
            : 'desktop'
        : 'desktop';
      await this.activityLogs.log({
        userId: userId || null,
        userType: userType || 'seeker',
        actionType: 'auth_logout',
        actionName: 'Logout',
        pageUrl: null,
        actionDetails: null,
        status: 'success',
        ipAddress: ip ? String(ip) : null,
        deviceType,
        browser: ua || null,
      });
    } catch (e) {
      // non-blocking
    }

    return { success: true, message: 'Logged out successfully' };
  }
}


