package repository

import (
	"context"
	"database/sql"
	"fmt"

	"git.godopu.com/lab/landing_page/backend/internal/models"
)

type StandardizationRepository struct {
	db *sql.DB
}

func NewStandardizationRepository(db *sql.DB) *StandardizationRepository {
	return &StandardizationRepository{db: db}
}

func (r *StandardizationRepository) GetStandardsBodiesWithProjects(ctx context.Context) ([]models.StandardsBodyWithProjects, error) {
	bodyQuery := `
		SELECT id, org, full_name, scope, period, role, display_order
		FROM standards_bodies
		ORDER BY display_order ASC, id ASC
	`
	bodyRows, err := r.db.QueryContext(ctx, bodyQuery)
	if err != nil {
		return nil, fmt.Errorf("query standards bodies: %w", err)
	}
	defer bodyRows.Close()

	var bodies []models.StandardsBodyWithProjects
	bodyMap := make(map[int]int)

	for bodyRows.Next() {
		var b models.StandardsBodyWithProjects
		if err := bodyRows.Scan(&b.ID, &b.Org, &b.FullName, &b.Scope, &b.Period, &b.Role, &b.DisplayOrder); err != nil {
			return nil, fmt.Errorf("scan standards body: %w", err)
		}
		b.Projects = []models.StandardProjectGroup{}
		bodyMap[b.ID] = len(bodies)
		bodies = append(bodies, b)
	}
	if err := bodyRows.Err(); err != nil {
		return nil, err
	}

	docQuery := `
		SELECT id, body_id, wg, project_name, title, doc_ref, status, published_at
		FROM standard_documents
		ORDER BY body_id ASC, id ASC
	`
	docRows, err := r.db.QueryContext(ctx, docQuery)
	if err != nil {
		return nil, fmt.Errorf("query standard documents: %w", err)
	}
	defer docRows.Close()

	type projectKey struct {
		bodyID      int
		wg          string
		projectName string
	}
	projectMap := make(map[projectKey]int)

	for docRows.Next() {
		var d models.StandardDocument
		if err := docRows.Scan(&d.ID, &d.BodyID, &d.WG, &d.ProjectName, &d.Title, &d.DocRef, &d.Status, &d.PublishedAt); err != nil {
			return nil, fmt.Errorf("scan standard document: %w", err)
		}

		bIdx, bodyExists := bodyMap[d.BodyID]
		if !bodyExists {
			continue
		}

		key := projectKey{bodyID: d.BodyID, wg: d.WG, projectName: d.ProjectName}
		pIdx, projExists := projectMap[key]
		if !projExists {
			pIdx = len(bodies[bIdx].Projects)
			bodies[bIdx].Projects = append(bodies[bIdx].Projects, models.StandardProjectGroup{
				WG:        d.WG,
				Name:      d.ProjectName,
				Documents: []models.StandardDocument{},
			})
			projectMap[key] = pIdx
		}

		bodies[bIdx].Projects[pIdx].Documents = append(bodies[bIdx].Projects[pIdx].Documents, d)
	}

	return bodies, docRows.Err()
}

func (r *StandardizationRepository) CreateStandardsBody(ctx context.Context, b models.StandardsBody) (int, error) {
	res, err := r.db.ExecContext(ctx, `
		INSERT INTO standards_bodies (org, full_name, scope, period, role, display_order)
		VALUES (?, ?, ?, ?, ?, ?)
	`, b.Org, b.FullName, b.Scope, b.Period, b.Role, b.DisplayOrder)
	if err != nil {
		return 0, fmt.Errorf("insert standards body: %w", err)
	}
	id, err := res.LastInsertId()
	return int(id), err
}

func (r *StandardizationRepository) UpdateStandardsBody(ctx context.Context, id int, b models.StandardsBody) error {
	res, err := r.db.ExecContext(ctx, `
		UPDATE standards_bodies
		SET org = ?, full_name = ?, scope = ?, period = ?, role = ?, display_order = ?
		WHERE id = ?
	`, b.Org, b.FullName, b.Scope, b.Period, b.Role, b.DisplayOrder, id)
	if err != nil {
		return fmt.Errorf("update standards body: %w", err)
	}
	rows, err := res.RowsAffected()
	if err == nil && rows == 0 {
		return sql.ErrNoRows
	}
	return err
}

func (r *StandardizationRepository) DeleteStandardsBody(ctx context.Context, id int) error {
	res, err := r.db.ExecContext(ctx, `DELETE FROM standards_bodies WHERE id = ?`, id)
	if err != nil {
		return fmt.Errorf("delete standards body: %w", err)
	}
	rows, err := res.RowsAffected()
	if err == nil && rows == 0 {
		return sql.ErrNoRows
	}
	return err
}

func (r *StandardizationRepository) CreateStandardDocument(ctx context.Context, d models.StandardDocument) (int, error) {
	res, err := r.db.ExecContext(ctx, `
		INSERT INTO standard_documents (body_id, wg, project_name, title, doc_ref, status, published_at)
		VALUES (?, ?, ?, ?, ?, ?, ?)
	`, d.BodyID, d.WG, d.ProjectName, d.Title, d.DocRef, d.Status, d.PublishedAt)
	if err != nil {
		return 0, fmt.Errorf("insert standard document: %w", err)
	}
	id, err := res.LastInsertId()
	return int(id), err
}

func (r *StandardizationRepository) UpdateStandardDocument(ctx context.Context, id int, d models.StandardDocument) error {
	res, err := r.db.ExecContext(ctx, `
		UPDATE standard_documents
		SET wg = ?, project_name = ?, title = ?, doc_ref = ?, status = ?, published_at = ?
		WHERE id = ?
	`, d.WG, d.ProjectName, d.Title, d.DocRef, d.Status, d.PublishedAt, id)
	if err != nil {
		return fmt.Errorf("update standard document: %w", err)
	}
	rows, err := res.RowsAffected()
	if err == nil && rows == 0 {
		return sql.ErrNoRows
	}
	return err
}

func (r *StandardizationRepository) DeleteStandardDocument(ctx context.Context, id int) error {
	res, err := r.db.ExecContext(ctx, `DELETE FROM standard_documents WHERE id = ?`, id)
	if err != nil {
		return fmt.Errorf("delete standard document: %w", err)
	}
	rows, err := res.RowsAffected()
	if err == nil && rows == 0 {
		return sql.ErrNoRows
	}
	return err
}
