package db

import (
	"database/sql"

	"github.com/openaccounting/oa-server/core/model/types"
	"github.com/openaccounting/oa-server/core/util"
)

const attachmentFields = "LOWER(HEX(id)),LOWER(HEX(transactionId)),LOWER(HEX(orgId)),LOWER(HEX(userId)),fileName,originalName,contentType,fileSize,filePath,description,uploaded,deleted"

type AttachmentInterface interface {
	InsertAttachment(*types.Attachment) error
	GetAttachment(string, string, string) (*types.Attachment, error)
	GetAttachmentsByTransaction(string, string) ([]*types.Attachment, error)
	DeleteAttachment(string, string, string) error
}

func (db *DB) InsertAttachment(attachment *types.Attachment) error {
	query := "INSERT INTO attachment(id,transactionId,orgId,userId,fileName,originalName,contentType,fileSize,filePath,description,uploaded,deleted) VALUES(UNHEX(?),UNHEX(?),UNHEX(?),UNHEX(?),?,?,?,?,?,?,?,?)"

	_, err := db.Exec(
		query,
		attachment.Id,
		attachment.TransactionId,
		attachment.OrgId,
		attachment.UserId,
		attachment.FileName,
		attachment.OriginalName,
		attachment.ContentType,
		attachment.FileSize,
		attachment.FilePath,
		attachment.Description,
		util.TimeToMs(attachment.Uploaded),
		attachment.Deleted,
	)

	return err
}

func (db *DB) GetAttachment(attachmentId, transactionId, orgId string) (*types.Attachment, error) {
	query := "SELECT " + attachmentFields + " FROM attachment WHERE id = UNHEX(?) AND transactionId = UNHEX(?) AND orgId = UNHEX(?) AND deleted = false"
	row := db.QueryRow(query, attachmentId, transactionId, orgId)

	return db.unmarshalAttachment(row)
}

func (db *DB) GetAttachmentsByTransaction(transactionId, orgId string) ([]*types.Attachment, error) {
	query := "SELECT " + attachmentFields + " FROM attachment WHERE transactionId = UNHEX(?) AND orgId = UNHEX(?) AND deleted = false ORDER BY uploaded DESC"
	rows, err := db.Query(query, transactionId, orgId)

	if err != nil {
		return nil, err
	}

	return db.unmarshalAttachments(rows)
}

func (db *DB) DeleteAttachment(attachmentId, transactionId, orgId string) error {
	query := "UPDATE attachment SET deleted = true WHERE id = UNHEX(?) AND transactionId = UNHEX(?) AND orgId = UNHEX(?)"
	_, err := db.Exec(query, attachmentId, transactionId, orgId)
	return err
}

func (db *DB) unmarshalAttachment(row *sql.Row) (*types.Attachment, error) {
	attachment := &types.Attachment{}
	var uploaded int64

	err := row.Scan(
		&attachment.Id,
		&attachment.TransactionId,
		&attachment.OrgId,
		&attachment.UserId,
		&attachment.FileName,
		&attachment.OriginalName,
		&attachment.ContentType,
		&attachment.FileSize,
		&attachment.FilePath,
		&attachment.Description,
		&uploaded,
		&attachment.Deleted,
	)

	if err != nil {
		return nil, err
	}

	attachment.Uploaded = util.MsToTime(uploaded)

	return attachment, nil
}

func (db *DB) unmarshalAttachments(rows *sql.Rows) ([]*types.Attachment, error) {
	defer rows.Close()

	attachments := []*types.Attachment{}

	for rows.Next() {
		attachment := &types.Attachment{}
		var uploaded int64

		err := rows.Scan(
			&attachment.Id,
			&attachment.TransactionId,
			&attachment.OrgId,
			&attachment.UserId,
			&attachment.FileName,
			&attachment.OriginalName,
			&attachment.ContentType,
			&attachment.FileSize,
			&attachment.FilePath,
			&attachment.Description,
			&uploaded,
			&attachment.Deleted,
		)

		if err != nil {
			return nil, err
		}

		attachment.Uploaded = util.MsToTime(uploaded)
		attachments = append(attachments, attachment)
	}

	return attachments, nil
}