package di

import (
	"context"
	"errors"
	"fmt"
	"io"
)

type Store interface {
	Get(context.Context, string) (string, error)
}
type Service struct{ store Store }

func NewService(store Store) (*Service, error) {
	if store == nil {
		return nil, errors.New("store is required")
	}
	return &Service{store: store}, nil
}
func (s *Service) Lookup(ctx context.Context, key string) (string, error) {
	return s.store.Get(ctx, key)
}

type Resource struct {
	out    io.Writer
	name   string
	closed bool
}

func Open(out io.Writer, name string) *Resource {
	fmt.Fprintln(out, "open", name)
	return &Resource{out: out, name: name}
}
func (r *Resource) Get(ctx context.Context, key string) (string, error) {
	if err := ctx.Err(); err != nil {
		return "", err
	}
	return "value:" + key, nil
}
func (r *Resource) Close() error {
	if !r.closed {
		fmt.Fprintln(r.out, "close", r.name)
		r.closed = true
	}
	return nil
}

type App struct {
	Service *Service
	close   func() error
}

func (a *App) Close() error { return a.close() }
func Build(out io.Writer, failHandler bool) (*App, error) {
	store := Open(out, "store")
	service, err := NewService(store)
	if err != nil {
		return nil, errors.Join(err, store.Close())
	}
	cache := Open(out, "cache")
	cleanup := func() error { return errors.Join(cache.Close(), store.Close()) }
	if failHandler {
		return nil, errors.Join(errors.New("handler setup failed"), cleanup())
	}
	return &App{Service: service, close: cleanup}, nil
}
