import { Email } from '../value-objects/Email';
import { Result } from '../value-objects/Result';

export interface UserProps {
  id: string;
  email: Email;
  name?: string;
  supabaseId: string;
  stripeCustomerId?: string;
  createdAt: Date;
  updatedAt: Date;
}

export class User {
  private constructor(private props: UserProps) {}

  static create(props: {
    id: string;
    email: string;
    name?: string;
    supabaseId: string;
    stripeCustomerId?: string;
    createdAt?: Date;
    updatedAt?: Date;
  }): Result<User> {
    const emailResult = this.validateEmail(props.email);
    if (emailResult.isFailure()) {
      return Result.fail(emailResult.getError());
    }

    const nameValidation = this.validateName(props.name);
    if (nameValidation.isFailure()) {
      return Result.fail(nameValidation.getError());
    }

    const user = this.buildUser(props, emailResult.getValue());
    return Result.ok(user);
  }

  private static validateEmail(email: string): Result<Email> {
    const emailObj = Email.create(email);
    return emailObj ? Result.ok(emailObj) : Result.fail('Invalid email address');
  }

  private static validateName(name?: string): Result<void> {
    if (name && name.length > 100) {
      return Result.fail('Name must be less than 100 characters');
    }
    return Result.ok(undefined);
  }

  private static buildUser(props: any, email: Email): User {
    return new User({
      id: props.id,
      email,
      name: props.name,
      supabaseId: props.supabaseId,
      stripeCustomerId: props.stripeCustomerId,
      createdAt: props.createdAt || new Date(),
      updatedAt: props.updatedAt || new Date(),
    });
  }

  getId(): string {
    return this.props.id;
  }

  getEmail(): Email {
    return this.props.email;
  }

  getName(): string | undefined {
    return this.props.name;
  }

  getSupabaseId(): string {
    return this.props.supabaseId;
  }

  getStripeCustomerId(): string | undefined {
    return this.props.stripeCustomerId;
  }

  setStripeCustomerId(customerId: string): void {
    this.props.stripeCustomerId = customerId;
    this.props.updatedAt = new Date();
  }

  updateName(name: string): Result<void> {
    if (name.length > 100) {
      return Result.fail('Name must be less than 100 characters');
    }

    this.props.name = name;
    this.props.updatedAt = new Date();

    return Result.ok(undefined);
  }

  hasStripeCustomer(): boolean {
    return !!this.props.stripeCustomerId;
  }

  toPlainObject() {
    return {
      id: this.props.id,
      email: this.props.email.getValue(),
      name: this.props.name,
      supabaseId: this.props.supabaseId,
      stripeCustomerId: this.props.stripeCustomerId,
      createdAt: this.props.createdAt,
      updatedAt: this.props.updatedAt,
    };
  }
}
