package models

import (
	"context"
	"database/sql"
	"screenmark/screenmark/.gen/haystack/haystack/model"
	. "screenmark/screenmark/.gen/haystack/haystack/table"

	. "github.com/go-jet/jet/v2/postgres"

	"github.com/google/uuid"
)

type ContactModel struct {
	dbPool *sql.DB
}

func (m ContactModel) List(ctx context.Context, userId uuid.UUID) ([]model.Contacts, error) {
	listContactsStmt := SELECT(Contacts.AllColumns).
		FROM(
			Contacts.
				INNER_JOIN(UserContacts, UserContacts.ContactID.EQ(Contacts.ID)),
		).
		WHERE(UserContacts.UserID.EQ(UUID(userId)))

	locations := []model.Contacts{}

	err := listContactsStmt.QueryContext(ctx, m.dbPool, &locations)
	return locations, err
}

func (m ContactModel) Get(ctx context.Context, contactId uuid.UUID) (model.Contacts, error) {
	getContactStmt := Contacts.
		SELECT(Contacts.AllColumns).
		WHERE(Contacts.ID.EQ(UUID(contactId)))

	contact := model.Contacts{}
	err := getContactStmt.QueryContext(ctx, m.dbPool, &contact)

	return contact, err
}

func (m ContactModel) Update(ctx context.Context, contact model.Contacts) (model.Contacts, error) {
	existingContact, err := m.Get(ctx, contact.ID)
	if err != nil {
		return model.Contacts{}, err
	}

	existingContact.Name = contact.Name

	if contact.Description != nil {
		existingContact.Description = contact.Description
	}

	if contact.PhoneNumber != nil {
		existingContact.PhoneNumber = contact.PhoneNumber
	}

	if contact.Email != nil {
		existingContact.Email = contact.Email
	}

	updateContactStmt := Contacts.
		UPDATE(Contacts.MutableColumns).
		MODEL(existingContact).
		WHERE(Contacts.ID.EQ(UUID(contact.ID))).
		RETURNING(Contacts.AllColumns)

	updatedContact := model.Contacts{}
	err = updateContactStmt.QueryContext(ctx, m.dbPool, &updatedContact)

	return updatedContact, err
}

func (m ContactModel) Save(ctx context.Context, userId uuid.UUID, contact model.Contacts) (model.Contacts, error) {
	// TODO: make this a transaction

	if contact.ID != uuid.Nil {
		return m.Update(ctx, contact)
	}

	insertContactStmt := Contacts.
		INSERT(Contacts.Name, Contacts.Description, Contacts.PhoneNumber, Contacts.Email).
		VALUES(contact.Name, contact.Description, contact.PhoneNumber, contact.Email).
		RETURNING(Contacts.AllColumns)

	insertedContact := model.Contacts{}
	err := insertContactStmt.QueryContext(ctx, m.dbPool, &insertedContact)

	if err != nil {
		return insertedContact, err
	}

	insertUserContactStmt := UserContacts.
		INSERT(UserContacts.UserID, UserContacts.ContactID).
		VALUES(userId, insertedContact.ID)

	_, err = insertUserContactStmt.ExecContext(ctx, m.dbPool)

	return insertedContact, err
}

func (m ContactModel) SaveToImage(ctx context.Context, imageId uuid.UUID, contactId uuid.UUID) (model.ImageContacts, error) {
	insertImageContactStmt := ImageContacts.
		INSERT(ImageContacts.ImageID, ImageContacts.ContactID).
		VALUES(imageId, contactId).
		RETURNING(ImageContacts.AllColumns)

	imageContact := model.ImageContacts{}
	err := insertImageContactStmt.QueryContext(ctx, m.dbPool, &imageContact)

	return imageContact, err
}

func NewContactModel(db *sql.DB) ContactModel {
	return ContactModel{dbPool: db}
}
