package storage

import (
	"encoding/json"
	"fmt"
	"os"
	"path/filepath"
	"sync"
	"time"

	"github.com/google/uuid"

	"mengyastore-backend/internal/models"
)

type OrderStore struct {
	path string
	mu   sync.Mutex
}

func NewOrderStore(path string) (*OrderStore, error) {
	if err := ensureOrdersFile(path); err != nil {
		return nil, err
	}
	return &OrderStore{path: path}, nil
}

func (s *OrderStore) Count() (int, error) {
	s.mu.Lock()
	defer s.mu.Unlock()

	items, err := s.readAll()
	if err != nil {
		return 0, err
	}
	return len(items), nil
}

func (s *OrderStore) ListByAccount(account string) ([]models.Order, error) {
	s.mu.Lock()
	defer s.mu.Unlock()

	items, err := s.readAll()
	if err != nil {
		return nil, err
	}
	matched := make([]models.Order, 0)
	for i := len(items) - 1; i >= 0; i-- {
		if items[i].UserAccount == account {
			matched = append(matched, items[i])
		}
	}
	return matched, nil
}

func (s *OrderStore) Confirm(id string) (models.Order, error) {
	s.mu.Lock()
	defer s.mu.Unlock()

	items, err := s.readAll()
	if err != nil {
		return models.Order{}, err
	}
	for i, item := range items {
		if item.ID == id {
			if item.Status == "completed" {
				return item, nil
			}
			items[i].Status = "completed"
			if err := s.writeAll(items); err != nil {
				return models.Order{}, err
			}
			return items[i], nil
		}
	}
	return models.Order{}, fmt.Errorf("order not found")
}

func (s *OrderStore) Create(order models.Order) (models.Order, error) {
	s.mu.Lock()
	defer s.mu.Unlock()

	items, err := s.readAll()
	if err != nil {
		return models.Order{}, err
	}

	order.ID = uuid.NewString()
	order.CreatedAt = time.Now()
	items = append(items, order)
	if err := s.writeAll(items); err != nil {
		return models.Order{}, err
	}
	return order, nil
}

func (s *OrderStore) readAll() ([]models.Order, error) {
	bytes, err := os.ReadFile(s.path)
	if err != nil {
		return nil, fmt.Errorf("read orders: %w", err)
	}
	var items []models.Order
	if err := json.Unmarshal(bytes, &items); err != nil {
		return nil, fmt.Errorf("parse orders: %w", err)
	}
	return items, nil
}

func (s *OrderStore) writeAll(items []models.Order) error {
	bytes, err := json.MarshalIndent(items, "", "  ")
	if err != nil {
		return fmt.Errorf("encode orders: %w", err)
	}
	if err := os.WriteFile(s.path, bytes, 0o644); err != nil {
		return fmt.Errorf("write orders: %w", err)
	}
	return nil
}

func ensureOrdersFile(path string) error {
	dir := filepath.Dir(path)
	if err := os.MkdirAll(dir, 0o755); err != nil {
		return fmt.Errorf("mkdir data dir: %w", err)
	}
	if _, err := os.Stat(path); err == nil {
		return nil
	} else if !os.IsNotExist(err) {
		return fmt.Errorf("stat data file: %w", err)
	}

	initial := []models.Order{}
	bytes, err := json.MarshalIndent(initial, "", "  ")
	if err != nil {
		return fmt.Errorf("init json: %w", err)
	}
	if err := os.WriteFile(path, bytes, 0o644); err != nil {
		return fmt.Errorf("write init json: %w", err)
	}
	return nil
}
