import { Inject, Injectable } from '@nestjs/common';
import type { Kysely } from 'kysely';
import { KYSELY_DB } from '../../database/src';
import type { Database } from '../../database/src';
import type { UserPreference, UserPreferenceFields } from './user.types';

function toUserPreference(row: {
  user_id: string;
  preferred_pace: string | null;
  preferred_budget_level: string | null;
  max_walking_distance_km: string | number | null;
  preferred_start_time: string | null;
  child_friendly_preferred: boolean;
  interests: string[];
  notes: string | null;
}): UserPreference {
  return {
    userId: row.user_id,
    preferredPace: row.preferred_pace,
    preferredBudgetLevel: row.preferred_budget_level,
    maxWalkingDistanceKm:
      row.max_walking_distance_km === null
        ? null
        : Number(row.max_walking_distance_km),
    preferredStartTime: row.preferred_start_time,
    childFriendlyPreferred: row.child_friendly_preferred,
    interests: row.interests,
    notes: row.notes,
  };
}

@Injectable()
export class UserPreferencesRepository {
  constructor(@Inject(KYSELY_DB) private readonly db: Kysely<Database>) {}

  async findByUserId(userId: string): Promise<UserPreference | undefined> {
    const row = await this.db
      .selectFrom('user_preferences')
      .selectAll()
      .where('user_id', '=', userId)
      .executeTakeFirst();
    return row ? toUserPreference(row) : undefined;
  }

  async upsert(
    userId: string,
    fields: UserPreferenceFields,
  ): Promise<UserPreference> {
    const values = {
      preferred_pace: fields.preferredPace,
      preferred_budget_level: fields.preferredBudgetLevel,
      max_walking_distance_km: fields.maxWalkingDistanceKm,
      preferred_start_time: fields.preferredStartTime,
      child_friendly_preferred: fields.childFriendlyPreferred,
      interests: fields.interests,
      notes: fields.notes,
    };

    const row = await this.db
      .insertInto('user_preferences')
      .values({ user_id: userId, ...values })
      .onConflict((oc) =>
        oc
          .column('user_id')
          .doUpdateSet({ ...values, updated_at: new Date().toISOString() }),
      )
      .returningAll()
      .executeTakeFirstOrThrow();

    return toUserPreference(row);
  }
}
