package docs

import (
	"context"
	"errors"

	"github.com/google/uuid"
	"github.com/jackc/pgx/v5"
	"github.com/jackc/pgx/v5/pgtype"
	"github.com/jackc/pgx/v5/pgxpool"

	docssqlc "github.com/yan1h/agent-coding-workflow/internal/docs/sqlc"
	"github.com/yan1h/agent-coding-workflow/internal/infra/errs"
)

// Repository is the docs persistence contract.
type Repository interface {
	Get(ctx context.Context, wsID uuid.UUID, commitSHA, kind string) (*Summary, error)
	Upsert(ctx context.Context, in UpsertInput) (*Summary, error)
}

// UpsertInput carries the fields for a commit_summaries upsert.
type UpsertInput struct {
	WorkspaceID uuid.UUID
	WorktreeID  *uuid.UUID
	Branch      string
	CommitSHA   string
	Kind        string
	Title       *string
	BodyMD      string
	Model       *string
	Status      string
	Error       *string
}

// PgRepository is the production Repository on a pgxpool.Pool.
type PgRepository struct {
	pool *pgxpool.Pool
	q    *docssqlc.Queries
}

// NewPostgresRepository builds a PgRepository.
func NewPostgresRepository(pool *pgxpool.Pool) *PgRepository {
	return &PgRepository{pool: pool, q: docssqlc.New(pool)}
}

var _ Repository = (*PgRepository)(nil)

func pgUUID(u uuid.UUID) pgtype.UUID { return pgtype.UUID{Bytes: u, Valid: true} }

func pgUUIDPtr(u *uuid.UUID) pgtype.UUID {
	if u == nil {
		return pgtype.UUID{}
	}
	return pgtype.UUID{Bytes: *u, Valid: true}
}

func uuidPtr(p pgtype.UUID) *uuid.UUID {
	if !p.Valid {
		return nil
	}
	id := uuid.UUID(p.Bytes)
	return &id
}

func summaryFromRow(r docssqlc.CommitSummary) *Summary {
	s := &Summary{
		ID:          uuid.UUID(r.ID.Bytes),
		WorkspaceID: uuid.UUID(r.WorkspaceID.Bytes),
		WorktreeID:  uuidPtr(r.WorktreeID),
		Branch:      r.Branch,
		CommitSHA:   r.CommitSha,
		Kind:        r.Kind,
		Title:       r.Title,
		BodyMD:      r.BodyMd,
		Model:       r.Model,
		Status:      r.Status,
		Error:       r.Error,
	}
	if r.CreatedAt.Valid {
		s.CreatedAt = r.CreatedAt.Time
	}
	return s
}

func (r *PgRepository) Get(ctx context.Context, wsID uuid.UUID, commitSHA, kind string) (*Summary, error) {
	row, err := r.q.GetSummary(ctx, docssqlc.GetSummaryParams{
		WorkspaceID: pgUUID(wsID),
		CommitSha:   commitSHA,
		Kind:        kind,
	})
	if err != nil {
		if errors.Is(err, pgx.ErrNoRows) {
			return nil, nil
		}
		return nil, errs.Wrap(err, errs.CodeInternal, "get commit summary")
	}
	return summaryFromRow(row), nil
}

func (r *PgRepository) Upsert(ctx context.Context, in UpsertInput) (*Summary, error) {
	kind := in.Kind
	if kind == "" {
		kind = KindCommit
	}
	status := in.Status
	if status == "" {
		status = StatusCompleted
	}
	row, err := r.q.UpsertSummary(ctx, docssqlc.UpsertSummaryParams{
		ID:          pgUUID(uuid.New()),
		WorkspaceID: pgUUID(in.WorkspaceID),
		WorktreeID:  pgUUIDPtr(in.WorktreeID),
		Branch:      in.Branch,
		CommitSha:   in.CommitSHA,
		Kind:        kind,
		Title:       in.Title,
		BodyMd:      in.BodyMD,
		Model:       in.Model,
		Status:      status,
		Error:       in.Error,
	})
	if err != nil {
		return nil, errs.Wrap(err, errs.CodeInternal, "upsert commit summary")
	}
	return summaryFromRow(row), nil
}
