package service

import (
	"crypto/rand"
	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	"time"
	"wails-app/internal/dao"
	"wails-app/internal/modules/digital-ticket/repository"
)

const (
	StateCreated        = "created"
	StatePendingPayment = "pending_payment"
	StatePaid           = "paid"
	StateExited         = "exited"
	StateExpired        = "expired"
)

type TicketService struct {
	repo *repository.TicketRepository
}

func NewTicketService() *TicketService {
	return &TicketService{repo: &repository.TicketRepository{}}
}

func genTicketNo() string {
	b := make([]byte, 16)
	rand.Read(b)
	return hex.EncodeToString(b)
}

func appendEvent(log string, event map[string]interface{}) string {
	var events []map[string]interface{}
	json.Unmarshal([]byte(log), &events)
	event["at"] = time.Now().Format(time.RFC3339)
	events = append(events, event)
	data, _ := json.Marshal(events)
	return string(data)
}

// Create 创建数字票（所有进场方式统一入口）
func (s *TicketService) Create(plateNumber, triggerMode string, recordID uint) (*dao.DigitalTicket, error) {
	log := appendEvent("[]", map[string]interface{}{"event": "created", "trigger": triggerMode})
	ticket := &dao.DigitalTicket{
		TicketNo: genTicketNo(), PlateNumber: plateNumber, TriggerMode: triggerMode,
		State: StatePendingPayment, VehicleRecordID: recordID, EntryTime: time.Now(), EventLog: log,
	}
	if err := s.repo.Create(ticket); err != nil {
		return nil, err
	}
	return ticket, nil
}

// Transition 状态转换（校验合法性，原子更新）
func (s *TicketService) Transition(id uint, toState string, extra map[string]interface{}) error {
	ticket, err := s.repo.GetByID(id)
	if err != nil {
		return errors.New("票不存在")
	}

	validTransitions := map[string][]string{
		StateCreated:        {StatePendingPayment},
		StatePendingPayment: {StatePaid, StateExpired},
		StatePaid:           {StateExited, StateExpired},
	}

	allowed := false
	for _, s := range validTransitions[ticket.State] {
		if s == toState {
			allowed = true
			break
		}
	}
	if !allowed {
		return fmt.Errorf("状态转换不合法: %s → %s", ticket.State, toState)
	}

	updates := map[string]interface{}{}
	if toState == StatePaid {
		now := time.Now()
		updates["paid_at"] = now
	}
	if toState == StateExited {
		now := time.Now()
		updates["exit_time"] = now
	}
	// 只允许表中存在的字段写入数据库，其余仅记录到事件日志
	dbFields := map[string]bool{"payment_method": true, "payment_order_no": true, "fee": true}
	for k, v := range extra {
		if dbFields[k] {
			updates[k] = v
		}
	}

	event := map[string]interface{}{"event": toState}
	for k, v := range extra {
		event[k] = v
	}
	updates["event_log"] = appendEvent(ticket.EventLog, event)

	return s.repo.UpdateState(id, toState, updates)
}

func (s *TicketService) GetByTicketNo(no string) (*dao.DigitalTicket, error) {
	return s.repo.GetByTicketNo(no)
}

func (s *TicketService) List(q repository.TicketListQuery) ([]dao.DigitalTicket, int64, error) {
	return s.repo.List(q)
}
