package repository

import (
	"errors"
	"time"
)

var (
	ErrUpdateFailed = errors.New("update failed")
	ErrDeleteFailed = errors.New("delete failed")
	ErrNotFound     = errors.New("record not found")
	ErrHasChildren  = errors.New("cannot delete: has dependent records that must be removed first")
)

// Repository is the interface which must be satisfied in order to
// connect to a database.
type Repository interface {
	Migrate() error

	InsertCompany(c Company) (*Company, error)
	AllCompanies() ([]Company, error)
	GetCompanyByID(id int64) (*Company, error)
	UpdateCompany(id int64, updated Company) error
	DeleteCompany(id int64) error

	InsertAssignment(a Assignment) (*Assignment, error)
	AssignmentsByCompany(companyID int64) ([]Assignment, error)
	AllActiveAssignments() ([]Assignment, error)
	GetAssignmentByID(id int64) (*Assignment, error)
	UpdateAssignment(id int64, updated Assignment) error
	DeleteAssignment(id int64) error

	InsertTask(t Task) (*Task, error)
	TasksByAssignment(assignmentID int64) ([]Task, error)
	GetTaskByID(id int64) (*Task, error)
	UpdateTask(id int64, name string) error
	DeleteTask(id int64) error
	TotalMinutesForTask(taskID int64) (float64, error)

	InsertWorkSession(s WorkSession) (*WorkSession, error)
	InsertManualWorkSession(s WorkSession) (*WorkSession, error)
	StopWorkSession(id int64) error
	UpdateWorkSession(id int64, updated WorkSession) error
	DeleteWorkSession(id int64) error
	WorkSessionsByAssignment(assignmentID int64, limit int) ([]WorkSession, error)
	TotalHoursForAssignment(assignmentID int64) (float64, error)

	NextInvoiceNumber(date time.Time) (string, error)
	InsertInvoice(inv Invoice) (*Invoice, error)
}

type Company struct {
	ID           int64     `json:"id"`
	Name         string    `json:"name"`
	Address      string    `json:"address"`
	ContactEmail string    `json:"contact_email"`
	ContactPhone string    `json:"contact_phone"`
	HourlyRate   float64   `json:"hourly_rate"`
	CreatedAt    time.Time `json:"created_at"`
}

type Assignment struct {
	ID          int64     `json:"id"`
	CompanyID   int64     `json:"company_id"`
	CompanyName string    `json:"company_name"`
	Name        string    `json:"name"`
	Description string    `json:"description"`
	HourlyRate  float64   `json:"hourly_rate"`
	Status      string    `json:"status"`
	CreatedAt   time.Time `json:"created_at"`
}

// Task is a reusable task within an assignment. Each task gets an
// incremental number scoped to its assignment (1, 2, 3...).
// Time spent on sessions with this task stacks up.
type Task struct {
	ID           int64   `json:"id"`
	AssignmentID int64   `json:"assignment_id"`
	Number       int     `json:"number"`
	Name         string  `json:"name"`
	TotalMinutes float64 `json:"total_minutes"`
}

// WorkSession is a single timed block of work on a task.
type WorkSession struct {
	ID              int64      `json:"id"`
	AssignmentID    int64      `json:"assignment_id"`
	TaskID          int64      `json:"task_id"`
	TaskDescription string     `json:"task_description"`
	StartTime       time.Time  `json:"start_time"`
	EndTime         *time.Time `json:"end_time"`
	DurationMinutes float64    `json:"duration_minutes"`
}

// Invoice is a generated invoice record, used for tracking invoice numbers.
type Invoice struct {
	ID            int64     `json:"id"`
	AssignmentID  int64     `json:"assignment_id"`
	InvoiceNumber string    `json:"invoice_number"`
	TotalAmount   float64   `json:"total_amount"`
	GeneratedAt   time.Time `json:"generated_at"`
}
