package queries

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

	"github.com/lib/pq"
)

type BrandRow struct {
	BrandCode string `json:"brand_code"`
	BrandName string `json:"brand_name"`
	GroupID   int    `json:"group_id"`
	GroupCode string `json:"group_code"`
	GroupName string `json:"group_name"`
}

type BrandGroupOption struct {
	ID          int    `json:"id"`
	Code        string `json:"code"`
	Title       string `json:"title"`
	Description string `json:"description"`
	AnchorMode  string `json:"anchor_mode"`
}

func EnsureBrandClassificationTables(pg *sql.DB) error {
	stmts := []string{
		`
CREATE TABLE IF NOT EXISTS mk_brands (
  brand_code TEXT PRIMARY KEY,
  brand_name TEXT NOT NULL DEFAULT '',
  is_active  BOOLEAN NOT NULL DEFAULT TRUE,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
)`,
		`CREATE INDEX IF NOT EXISTS ix_mk_brands_name ON mk_brands (brand_name)`,
		`
CREATE TABLE IF NOT EXISTS mk_brandgrp (
  id          SMALLINT PRIMARY KEY,
  code        TEXT NOT NULL UNIQUE,
  title       TEXT NOT NULL,
  description TEXT NOT NULL DEFAULT '',
  anchor_mode TEXT NOT NULL DEFAULT 'USD',
  sort_order  SMALLINT NOT NULL DEFAULT 0,
  created_at  TIMESTAMPTZ NOT NULL DEFAULT now()
)`,
		`ALTER TABLE mk_brandgrp ADD COLUMN IF NOT EXISTS description TEXT NOT NULL DEFAULT ''`,
		`ALTER TABLE mk_brandgrp ADD COLUMN IF NOT EXISTS anchor_mode TEXT NOT NULL DEFAULT 'USD'`,
		`UPDATE mk_brandgrp SET anchor_mode='USD' WHERE COALESCE(NULLIF(BTRIM(anchor_mode), ''), '') = ''`,
		`ALTER TABLE mk_brandgrp DROP CONSTRAINT IF EXISTS ck_mk_brandgrp_anchor_mode`,
		`ALTER TABLE mk_brandgrp ADD CONSTRAINT ck_mk_brandgrp_anchor_mode CHECK (anchor_mode IN ('TRY','USD'))`,
		`
INSERT INTO mk_brandgrp (id, code, title, description, sort_order)
VALUES
  (1, 'SARTORIAL', 'SARTORIAL', 'Klasik / terzilik odakli ana marka grubu', 1),
  (2, 'PREMIUM',   'PREMIUM',   'Ust segment / premium koleksiyon marka grubu', 2),
  (3, 'CORE',      'CORE',      'Ana koleksiyon / temel marka grubu', 3)
ON CONFLICT (id) DO NOTHING`,
		`UPDATE mk_brandgrp SET description='Klasik / terzilik odakli ana marka grubu' WHERE id=1 AND COALESCE(description,'')=''`,
		`UPDATE mk_brandgrp SET description='Ust segment / premium koleksiyon marka grubu' WHERE id=2 AND COALESCE(description,'')=''`,
		`UPDATE mk_brandgrp SET description='Ana koleksiyon / temel marka grubu' WHERE id=3 AND COALESCE(description,'')=''`,
		`
CREATE TABLE IF NOT EXISTS mk_brandgrpmatch (
  brand_code  TEXT NOT NULL REFERENCES mk_brands(brand_code) ON DELETE CASCADE,
  grp_id      SMALLINT NOT NULL REFERENCES mk_brandgrp(id) ON DELETE RESTRICT,
  created_at  TIMESTAMPTZ NOT NULL DEFAULT now(),
  updated_at  TIMESTAMPTZ NOT NULL DEFAULT now(),
  PRIMARY KEY (brand_code)
)`,
		`CREATE INDEX IF NOT EXISTS ix_mk_brandgrpmatch_grp ON mk_brandgrpmatch (grp_id)`,
	}
	for _, s := range stmts {
		if _, err := pg.Exec(s); err != nil {
			return err
		}
	}
	return nil
}

func ListBrandGroups(ctx context.Context, pg *sql.DB) ([]BrandGroupOption, error) {
	rows, err := pg.QueryContext(ctx, `SELECT id, code, title, description, anchor_mode FROM mk_brandgrp ORDER BY sort_order, id`)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	out := make([]BrandGroupOption, 0, 8)
	for rows.Next() {
		var o BrandGroupOption
		if err := rows.Scan(&o.ID, &o.Code, &o.Title, &o.Description, &o.AnchorMode); err != nil {
			return nil, err
		}
		o.Code = strings.TrimSpace(o.Code)
		o.Title = strings.TrimSpace(o.Title)
		o.Description = strings.TrimSpace(o.Description)
		o.AnchorMode = strings.ToUpper(strings.TrimSpace(o.AnchorMode))
		if o.AnchorMode == "" {
			o.AnchorMode = "USD"
		}
		out = append(out, o)
	}
	return out, rows.Err()
}

func SetBrandGroupAnchorMode(ctx context.Context, tx *sql.Tx, grpID int, anchorMode string) error {
	anchorMode = strings.ToUpper(strings.TrimSpace(anchorMode))
	if anchorMode == "" {
		anchorMode = "USD"
	}
	_, err := tx.ExecContext(ctx, `
UPDATE mk_brandgrp
SET anchor_mode=$2
WHERE id=$1
`, grpID, anchorMode)
	return err
}

func SyncPricingRuleAnchorModesByGroup(ctx context.Context, tx *sql.Tx, grpID int, anchorMode string) error {
	anchorMode = strings.ToUpper(strings.TrimSpace(anchorMode))
	if anchorMode == "" {
		anchorMode = "USD"
	}
	_, err := tx.ExecContext(ctx, `
UPDATE mk_pricing_rule r
SET anchor_mode=$2,
    updated_at=now()
WHERE EXISTS (
  SELECT 1
  FROM mk_brandgrp g
  JOIN LATERAL unnest(r.brand_group) bg(value) ON TRUE
  WHERE g.id=$1
    AND (
      UPPER(BTRIM(bg.value)) = UPPER(BTRIM(g.code))
      OR UPPER(BTRIM(bg.value)) = UPPER(BTRIM(g.title))
    )
)
`, grpID, anchorMode)
	return err
}

func ListBrandsWithGroups(ctx context.Context, pg *sql.DB, q string, limit int) ([]BrandRow, error) {
	if limit <= 0 {
		limit = 5000
	}
	q = strings.TrimSpace(q)
	args := []any{}
	where := ""
	if q != "" {
		args = append(args, "%"+q+"%")
		where = "WHERE (b.brand_code ILIKE $1 OR b.brand_name ILIKE $1)"
	}
	args = append(args, limit)

	limitParam := fmt.Sprintf("$%d", len(args))
	sqlq := `
SELECT
  b.brand_code,
  b.brand_name,
  COALESCE(m.grp_id, 0) AS group_id,
  COALESCE(g.code, '') AS group_code,
  COALESCE(g.title, '') AS group_name
FROM mk_brands b
LEFT JOIN mk_brandgrpmatch m ON m.brand_code = b.brand_code
LEFT JOIN mk_brandgrp g ON g.id = m.grp_id
` + where + `
ORDER BY b.brand_code
LIMIT ` + limitParam + `
`
	rows, err := pg.QueryContext(ctx, sqlq, args...)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	out := make([]BrandRow, 0, 1024)
	for rows.Next() {
		var r BrandRow
		if err := rows.Scan(&r.BrandCode, &r.BrandName, &r.GroupID, &r.GroupCode, &r.GroupName); err != nil {
			return nil, err
		}
		r.BrandCode = strings.TrimSpace(r.BrandCode)
		r.BrandName = strings.TrimSpace(r.BrandName)
		r.GroupCode = strings.TrimSpace(r.GroupCode)
		r.GroupName = strings.TrimSpace(r.GroupName)
		out = append(out, r)
	}
	return out, rows.Err()
}

func UpsertBrand(ctx context.Context, tx *sql.Tx, code string, name string, active bool) error {
	code = strings.TrimSpace(code)
	name = strings.TrimSpace(name)
	if code == "" {
		return nil
	}
	_, err := tx.ExecContext(ctx, `
INSERT INTO mk_brands (brand_code, brand_name, is_active, created_at, updated_at)
VALUES ($1, $2, $3, now(), now())
ON CONFLICT (brand_code) DO UPDATE SET
  brand_name = EXCLUDED.brand_name,
  is_active  = EXCLUDED.is_active,
  updated_at = now()
`, code, name, active)
	return err
}

func DeleteBrandsNotIn(ctx context.Context, tx *sql.Tx, keepCodes []string) error {
	// If keepCodes is empty, do nothing (avoid wiping table by mistake).
	if len(keepCodes) == 0 {
		return nil
	}
	// Use temp table style deletion via UNNEST.
	_, err := tx.ExecContext(ctx, `
DELETE FROM mk_brands
WHERE brand_code NOT IN (SELECT UNNEST($1::text[]))
`, pq.Array(keepCodes))
	return err
}

func SetBrandGroup(ctx context.Context, tx *sql.Tx, brandCode string, grpID int) error {
	brandCode = strings.TrimSpace(brandCode)
	if brandCode == "" {
		return nil
	}
	if grpID <= 0 {
		_, err := tx.ExecContext(ctx, `DELETE FROM mk_brandgrpmatch WHERE brand_code=$1`, brandCode)
		return err
	}
	_, err := tx.ExecContext(ctx, `
INSERT INTO mk_brandgrpmatch (brand_code, grp_id, created_at, updated_at)
VALUES ($1, $2, now(), now())
ON CONFLICT (brand_code) DO UPDATE SET
  grp_id = EXCLUDED.grp_id,
  updated_at = now()
`, brandCode, grpID)
	return err
}
