// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0

package postgres

import (
	"database/sql"
	"encoding/json"
	"time"

	"github.com/absmach/magistrala/pkg/errors"
	"github.com/absmach/magistrala/pkg/roles"
	"github.com/absmach/magistrala/pkg/schedule"
	"github.com/absmach/magistrala/reports"
	"github.com/lib/pq"
)

// dbReport represents the database structure for a Report.
type dbReport struct {
	ID                        string                 `db:"id"`
	Name                      string                 `db:"name"`
	Description               string                 `db:"description"`
	DomainID                  string                 `db:"domain_id"`
	StartDateTime             sql.NullTime           `db:"start_datetime"`
	Due                       sql.NullTime           `db:"due"`
	Recurring                 schedule.Recurring     `db:"recurring"`
	RecurringPeriod           uint                   `db:"recurring_period"`
	Status                    reports.Status         `db:"status"`
	CreatedAt                 time.Time              `db:"created_at"`
	CreatedBy                 string                 `db:"created_by"`
	UpdatedAt                 time.Time              `db:"updated_at"`
	UpdatedBy                 string                 `db:"updated_by"`
	Config                    []byte                 `db:"config,omitempty"`
	Metrics                   []byte                 `db:"metrics"`
	Email                     []byte                 `db:"email"`
	ReportTemplate            reports.ReportTemplate `db:"report_template"`
	MemberID                  string                 `db:"member_id,omitempty"`
	RoleID                    string                 `db:"role_id,omitempty"`
	RoleName                  string                 `db:"role_name,omitempty"`
	Actions                   pq.StringArray         `db:"actions,omitempty"`
	AccessType                string                 `db:"access_type,omitempty"`
	AccessProviderId          string                 `db:"access_provider_id,omitempty"`
	AccessProviderRoleId      string                 `db:"access_provider_role_id,omitempty"`
	AccessProviderRoleName    string                 `db:"access_provider_role_name,omitempty"`
	AccessProviderRoleActions pq.StringArray         `db:"access_provider_role_actions,omitempty"`
	Roles                     json.RawMessage        `db:"roles,omitempty"`
}

func reportToDb(r reports.ReportConfig) (dbReport, error) {
	config := []byte("{}")
	if r.Config != nil {
		b, err := json.Marshal(r.Config)
		if err != nil {
			return dbReport{}, errors.Wrap(errors.ErrMalformedEntity, err)
		}
		config = b
	}

	metrics := []byte("{}")
	if r.Metrics != nil {
		m, err := json.Marshal(r.Metrics)
		if err != nil {
			return dbReport{}, errors.Wrap(errors.ErrMalformedEntity, err)
		}
		metrics = m
	}

	email := []byte("{}")
	if r.Email != nil {
		e, err := json.Marshal(r.Email)
		if err != nil {
			return dbReport{}, errors.Wrap(errors.ErrMalformedEntity, err)
		}
		email = e
	}
	start := sql.NullTime{Time: r.Schedule.StartDateTime}
	if !r.Schedule.StartDateTime.IsZero() {
		start.Valid = true
	}
	t := sql.NullTime{Time: r.Schedule.Time}
	if !r.Schedule.Time.IsZero() {
		t.Valid = true
	}

	return dbReport{
		ID:              r.ID,
		Name:            r.Name,
		Description:     r.Description,
		DomainID:        r.DomainID,
		StartDateTime:   start,
		Due:             t,
		Recurring:       r.Schedule.Recurring,
		RecurringPeriod: r.Schedule.RecurringPeriod,
		Status:          r.Status,
		CreatedAt:       r.CreatedAt,
		CreatedBy:       r.CreatedBy,
		UpdatedAt:       r.UpdatedAt,
		UpdatedBy:       r.UpdatedBy,
		Config:          config,
		Metrics:         metrics,
		Email:           email,
		ReportTemplate:  r.ReportTemplate,
	}, nil
}

func dbToReport(dto dbReport) (reports.ReportConfig, error) {
	var config reports.MetricConfig
	if dto.Config != nil {
		if err := json.Unmarshal(dto.Config, &config); err != nil {
			return reports.ReportConfig{}, errors.Wrap(errors.ErrMalformedEntity, err)
		}
	}

	var email reports.EmailSetting
	if dto.Email != nil {
		if err := json.Unmarshal(dto.Email, &email); err != nil {
			return reports.ReportConfig{}, errors.Wrap(errors.ErrMalformedEntity, err)
		}
	}

	var metrics []reports.ReqMetric
	if dto.Metrics != nil {
		if err := json.Unmarshal(dto.Metrics, &metrics); err != nil {
			return reports.ReportConfig{}, errors.Wrap(errors.ErrMalformedEntity, err)
		}
	}

	var roles []roles.MemberRoleActions
	if dto.Roles != nil {
		if err := json.Unmarshal(dto.Roles, &roles); err != nil {
			return reports.ReportConfig{}, errors.Wrap(errors.ErrMalformedEntity, err)
		}
	}

	rpt := reports.ReportConfig{
		ID:          dto.ID,
		Name:        dto.Name,
		Description: dto.Description,
		DomainID:    dto.DomainID,
		Config:      &config,
		Metrics:     metrics,
		Schedule: schedule.Schedule{
			StartDateTime:   dto.StartDateTime.Time,
			Time:            dto.Due.Time,
			Recurring:       dto.Recurring,
			RecurringPeriod: dto.RecurringPeriod,
		},
		Email:                     &email,
		Status:                    dto.Status,
		CreatedAt:                 dto.CreatedAt,
		CreatedBy:                 dto.CreatedBy,
		UpdatedAt:                 dto.UpdatedAt,
		UpdatedBy:                 dto.UpdatedBy,
		ReportTemplate:            dto.ReportTemplate,
		RoleID:                    dto.RoleID,
		RoleName:                  dto.RoleName,
		Actions:                   []string(dto.Actions),
		AccessType:                dto.AccessType,
		AccessProviderId:          dto.AccessProviderId,
		AccessProviderRoleId:      dto.AccessProviderRoleId,
		AccessProviderRoleName:    dto.AccessProviderRoleName,
		AccessProviderRoleActions: []string(dto.AccessProviderRoleActions),
		Roles:                     roles,
	}

	return rpt, nil
}
