package models

import (
	"fmt"
	"time"

	"github.com/alexedwards/argon2id"
	"gorm.io/gorm"
)

type User struct {
	ID             uint `gorm:"primarykey" json:"id"`
	CreatedAt      time.Time
	UpdatedAt      time.Time
	DeletedAt      *time.Time  `gorm:"index"`
	DateOfBirth    time.Time   `gorm:"not null" json:"dateofbirth" binding:"required,safe_content"`
	Company        string      `json:"company" binding:"omitempty,omitnil,safe_content"`
	Phone          string      `json:"phone" binding:"omitempty,omitnil,safe_content"`
	Notes          string      `json:"notes" binding:"safe_content"`
	FirstName      string      `gorm:"not null" json:"first_name" binding:"required,safe_content"`
	Password       string      `json:"password" binding:"safe_content"`
	Email          string      `gorm:"unique;not null" json:"email" binding:"required,email,safe_content"`
	LastName       string      `gorm:"not null" json:"last_name" binding:"required,safe_content"`
	ProfilePicture string      `json:"profile_picture" binding:"omitempty,omitnil,image,safe_content"`
	Address        string      `gorm:"not null" json:"address" binding:"required,safe_content"`
	ZipCode        string      `gorm:"not null" json:"zip_code" binding:"required,alphanum,safe_content"`
	City           string      `form:"not null" json:"city" binding:"required,alphaunicode,safe_content"`
	Consents       []Consent   `gorm:"constraint:OnUpdate:CASCADE"`
	BankAccount    BankAccount `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"bank_account"`
	BankAccountID  uint
	Verification   Verification `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;"`
	VerificationID uint
	Membership     Membership `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"membership"`
	MembershipID   uint
	Licence        *Licence `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"licence"`
	LicenceID      uint
	PaymentStatus  int8 `json:"payment_status"`
	Status         int8 `json:"status"`
	RoleID         int8 `json:"role_id"`
}

func (u *User) AfterCreate(tx *gorm.DB) (err error) {
	if u.BankAccount.ID != 0 && u.BankAccount.MandateReference == "" {
		mandateReference := u.GenerateMandateReference()

		return tx.Model(&u.BankAccount).Update("MandateReference", mandateReference).Error
	}
	return nil
}

func (u *User) GenerateMandateReference() string {
	return fmt.Sprintf("%s%d%s", time.Now().Format("20060102"), u.ID, u.BankAccount.IBAN)
}

func (u *User) PasswordMatches(plaintextPassword string) (bool, error) {
	match, err := argon2id.ComparePasswordAndHash(plaintextPassword, u.Password)
	if err != nil {
		return false, err
	}

	return match, nil
}

func (u *User) Safe() map[string]interface{} {
	result := map[string]interface{}{
		"email":       u.Email,
		"first_name":  u.FirstName,
		"last_name":   u.LastName,
		"phone":       u.Phone,
		"notes":       u.Notes,
		"address":     u.Address,
		"zip_code":    u.ZipCode,
		"city":        u.City,
		"status":      u.Status,
		"id":          u.ID,
		"role_id":     u.RoleID,
		"company":     u.Company,
		"dateofbirth": u.DateOfBirth,
		"membership": map[string]interface{}{
			"id":         u.Membership.ID,
			"start_date": u.Membership.StartDate,
			"end_date":   u.Membership.EndDate,
			"status":     u.Membership.Status,
			"subscription_model": map[string]interface{}{
				"id":                 u.Membership.SubscriptionModel.ID,
				"name":               u.Membership.SubscriptionModel.Name,
				"details":            u.Membership.SubscriptionModel.Details,
				"conditions":         u.Membership.SubscriptionModel.Conditions,
				"monthly_fee":        u.Membership.SubscriptionModel.MonthlyFee,
				"hourly_rate":        u.Membership.SubscriptionModel.HourlyRate,
				"included_per_year":  u.Membership.SubscriptionModel.IncludedPerYear,
				"included_per_month": u.Membership.SubscriptionModel.IncludedPerMonth,
			},
		},
		"licence": map[string]interface{}{
			"id": 0,
		},
		"bank_account": map[string]interface{}{
			"id":                  u.BankAccount.ID,
			"mandate_date_signed": u.BankAccount.MandateDateSigned,
			"bank":                u.BankAccount.Bank,
			"account_holder_name": u.BankAccount.AccountHolderName,
			"iban":                u.BankAccount.IBAN,
			"bic":                 u.BankAccount.BIC,
			"mandate_reference":   u.BankAccount.MandateReference,
		},
	}

	if u.Licence != nil {
		result["licence"] = map[string]interface{}{
			"id":              u.Licence.ID,
			"number":          u.Licence.Number,
			"status":          u.Licence.Status,
			"issued_date":     u.Licence.IssuedDate,
			"expiration_date": u.Licence.ExpirationDate,
			"country":         u.Licence.IssuingCountry,
			"categories":      u.Licence.Categories,
		}
	}

	return result
}
