package queries

import (
	"bssapp-backend/db"
	"bssapp-backend/internal/i18n"
	"bssapp-backend/models"
	"context"
	"database/sql"
	"fmt"
	"strings"
)

// Ana tabloyu getiren fonksiyon (Vue header tablosu için)
func GetStatements(ctx context.Context, params models.StatementParams) ([]models.StatementHeader, error) {

	// AccountCode normalize: "ZLA0127" → "ZLA 0127"
	params.AccountCode = normalizeMasterAccountCode(params.AccountCode)
	params.LangCode = i18n.NormalizeLangCode(params.LangCode)

	// Parislemler []string → '1','2','3'
	parislemFilter := "''"
	if len(params.Parislemler) > 0 {
		quoted := make([]string, 0, len(params.Parislemler))
		for _, v := range params.Parislemler {
			v = strings.TrimSpace(v)
			if v == "" {
				continue
			}
			quoted = append(quoted, fmt.Sprintf("'%s'", strings.ReplaceAll(v, "'", "''")))
		}
		if len(quoted) > 0 {
			parislemFilter = strings.Join(quoted, ",")
		}
	}

	customerPiyasaInClause, err := resolvePiyasaScopeInClause(ctx, "PF.CustomerAtt01")
	if err != nil {
		return nil, err
	}
	vendorPiyasaInClause, err := resolvePiyasaScopeInClause(ctx, "VF.VendorAtt01")
	if err != nil {
		return nil, err
	}

	piyasaScope := fmt.Sprintf(`
(
    (b.CurrAccTypeCode = 3 AND EXISTS (
        SELECT 1
        FROM CustomerAttributesFilter PF
        WHERE (PF.CurrAccCode = b.CurrAccCode OR LEFT(PF.CurrAccCode, 8) = LEFT(b.CurrAccCode, 8))
          AND %s
    ))
    OR
    (b.CurrAccTypeCode = 1 AND EXISTS (
        SELECT 1
        FROM (
            SELECT
                CurrAccCode,
                VendorAtt01 = MAX(CASE WHEN AttributeTypeCode = 1 THEN AttributeCode END)
            FROM prCurrAccAttribute
            WHERE CurrAccTypeCode = 1
            GROUP BY CurrAccCode
        ) VF
        WHERE (VF.CurrAccCode = b.CurrAccCode OR LEFT(VF.CurrAccCode, 8) = LEFT(b.CurrAccCode, 8))
          AND %s
    ))
)`, customerPiyasaInClause, vendorPiyasaInClause)

	query := fmt.Sprintf(`
;WITH CurrDesc AS (
    SELECT
        CurrAccCode,
        MAX(CurrAccDescription) AS CurrAccDescription
    FROM cdCurrAccDesc
    WHERE LangCode = @LangCode
    GROUP BY CurrAccCode
),

/* =========================================================
   ✅ Bu aralıkta hareket var mı?
   Varsa : Devir = startdate öncesi
   Yoksa : Devir = enddate dahil (enddate itibariyle bakiye)
   ========================================================= */
HasMovement AS (
    SELECT
        CASE WHEN EXISTS (
            SELECT 1
            FROM trCurrAccBook b
            INNER JOIN CurrAccBookATAttributesFilter f
              ON f.CurrAccBookID = b.CurrAccBookID
             AND f.ATAtt01 IN (%s)
            WHERE LEFT(REPLACE(b.CurrAccCode, ' ', ''), 7) = LEFT(REPLACE(@Carikod, ' ', ''), 7)
              AND b.DocumentDate BETWEEN @startdate AND @enddate
              AND %s
        ) THEN 1 ELSE 0 END AS HasMov
),

/* =========================================================
   ✅ Opening (Devir) — TEK CARİ KOD ALTINDA KONSOLİDE
   Cari_Kod = @Carikod (sabit)
   ========================================================= */
Opening AS (
    SELECT
        @Carikod           AS Cari_Kod,
        b.DocCurrencyCode  AS Para_Birimi,
        SUM(ISNULL(c.Debit,0) - ISNULL(c.Credit,0)) AS Devir_Bakiyesi
    FROM trCurrAccBook b
    CROSS JOIN HasMovement hm
    INNER JOIN CurrAccBookATAttributesFilter f2
      ON f2.CurrAccBookID = b.CurrAccBookID
     AND f2.ATAtt01 IN (%s)
    LEFT JOIN trCurrAccBookCurrency c
      ON c.CurrAccBookID = b.CurrAccBookID
     AND c.CurrencyCode  = b.DocCurrencyCode
    WHERE LEFT(REPLACE(b.CurrAccCode, ' ', ''), 7) = LEFT(REPLACE(@Carikod, ' ', ''), 7)
      AND @ExcludeOpening = 0
      AND %s
      AND (
            (hm.HasMov = 1 AND b.DocumentDate <  @startdate)  -- hareket varsa: klasik devir
         OR (hm.HasMov = 0 AND b.DocumentDate <= @enddate)    -- hareket yoksa: enddate itibariyle bakiye
      )
    GROUP BY b.DocCurrencyCode
),

/* =========================================================
   ✅ Hareketler (Movements) — TEK CARİ KOD ALTINDA KONSOLİDE
   Cari_Kod = @Carikod (sabit)
   Running sadece aralıktaki hareketlerden gelir.
   ========================================================= */
Movements AS (
    SELECT
        @Carikod AS Ana_Cari_Kod,
        b.CurrAccCode AS Cari_Kod,

        COALESCE(
            (SELECT TOP 1 cd.CurrAccDescription
             FROM CurrDesc cd
             WHERE REPLACE(cd.CurrAccCode, ' ', '') = REPLACE(b.CurrAccCode, ' ', '')),
            (SELECT TOP 1 cd.CurrAccDescription
             FROM CurrDesc cd
             WHERE LEFT(REPLACE(cd.CurrAccCode, ' ', ''), 7) = REPLACE(@Carikod, ' ', '')
             ORDER BY cd.CurrAccCode)
        ) AS Cari_Isim,

        CONVERT(varchar(10), b.DocumentDate, 23) AS Belge_Tarihi,
        CONVERT(varchar(10), b.DueDate, 23)      AS Vade_Tarihi,

        b.RefNumber           AS Belge_No,
        b.BaseApplicationCode AS Islem_Tipi,
        b.LineDescription     AS Aciklama,

        b.DocCurrencyCode     AS Para_Birimi,

        ISNULL(c.Debit,0)     AS Borc,
        ISNULL(c.Credit,0)    AS Alacak,

        SUM(ISNULL(c.Debit,0) - ISNULL(c.Credit,0))
            OVER (
              PARTITION BY b.DocCurrencyCode
              ORDER BY b.DocumentDate, b.CurrAccBookID
            ) AS Hareket_Bakiyesi,

        f.ATAtt01 AS Parislemtipi

    FROM trCurrAccBook b
    INNER JOIN CurrAccBookATAttributesFilter f
      ON f.CurrAccBookID = b.CurrAccBookID
     AND f.ATAtt01 IN (%s)
    LEFT JOIN trCurrAccBookCurrency c
      ON c.CurrAccBookID = b.CurrAccBookID
     AND c.CurrencyCode  = b.DocCurrencyCode

    WHERE LEFT(REPLACE(b.CurrAccCode, ' ', ''), 7) = LEFT(REPLACE(@Carikod, ' ', ''), 7)
      AND %s
      AND b.DocumentDate BETWEEN @startdate AND @enddate
)

SELECT
    m.Cari_Kod,
    m.Cari_Isim,
    m.Belge_Tarihi,
    m.Vade_Tarihi,
    m.Belge_No,
    m.Islem_Tipi,
    m.Aciklama,
    m.Para_Birimi,
    m.Borc,
    m.Alacak,

    /* ✅ Bakiye = Devir + Aralıktaki Running */
    ISNULL(o.Devir_Bakiyesi,0) + m.Hareket_Bakiyesi AS Bakiye,

    m.Parislemtipi AS Parislemler

FROM Movements m
LEFT JOIN Opening o
  ON o.Cari_Kod    = m.Ana_Cari_Kod
 AND o.Para_Birimi = m.Para_Birimi

UNION ALL

/* =========================================================
   ✅ Devir Satırı (kur bazında) — Opening'den gelir
   Hareket varsa: startdate öncesi
   Hareket yoksa: enddate itibariyle bakiye
   ========================================================= */
SELECT
    o.Cari_Kod,
    COALESCE(
        (SELECT TOP 1 cd.CurrAccDescription
         FROM CurrDesc cd
         WHERE REPLACE(cd.CurrAccCode, ' ', '') = REPLACE(o.Cari_Kod, ' ', '')),
        (SELECT TOP 1 cd.CurrAccDescription
         FROM CurrDesc cd
         WHERE LEFT(REPLACE(cd.CurrAccCode, ' ', ''), 7) = REPLACE(@Carikod, ' ', '')
         ORDER BY cd.CurrAccCode)
    ) AS Cari_Isim,

    CONVERT(varchar(10), @startdate, 23) AS Belge_Tarihi,
    CONVERT(varchar(10), @startdate, 23) AS Vade_Tarihi,

    'Baslangic_devir' AS Belge_No,
    CASE WHEN @LangCode = 'EN' THEN 'Opening' ELSE 'Devir' END AS Islem_Tipi,
    CASE WHEN @LangCode = 'EN' THEN 'Opening Balance' ELSE 'Devir Bakiyesi' END AS Aciklama,

    o.Para_Birimi,

    CASE WHEN o.Devir_Bakiyesi >= 0 THEN o.Devir_Bakiyesi ELSE 0 END AS Borc,
    CASE WHEN o.Devir_Bakiyesi <  0 THEN ABS(o.Devir_Bakiyesi) ELSE 0 END AS Alacak,

    o.Devir_Bakiyesi AS Bakiye,

    CAST(NULL AS varchar(32)) AS Parislemler

FROM Opening o

ORDER BY
    Para_Birimi,
    Belge_Tarihi;
`,
		parislemFilter, // HasMovement ATAtt01
		piyasaScope,    // HasMovement piyasa scope
		parislemFilter, // Opening ATAtt01
		piyasaScope,    // Opening piyasa scope
		parislemFilter, // Movements ATAtt01
		piyasaScope,    // Movements piyasa scope
	)

	rows, err := db.MssqlDB.QueryContext(ctx, query,
		sql.Named("startdate", params.StartDate),
		sql.Named("enddate", params.EndDate),
		sql.Named("Carikod", params.AccountCode),
		sql.Named("LangCode", params.LangCode),
		sql.Named("ExcludeOpening", params.ExcludeOpening),
	)
	if err != nil {
		return nil, fmt.Errorf("MSSQL query error: %v", err)
	}
	defer rows.Close()

	var results []models.StatementHeader
	for rows.Next() {
		var r models.StatementHeader
		if err := rows.Scan(
			&r.CariKod,
			&r.CariIsim,
			&r.BelgeTarihi,
			&r.VadeTarihi,
			&r.BelgeNo,
			&r.IslemTipi,
			&r.Aciklama,
			&r.ParaBirimi,
			&r.Borc,
			&r.Alacak,
			&r.Bakiye,
			&r.Parislemler,
		); err != nil {
			return nil, err
		}
		results = append(results, r)
	}
	return results, nil
}

func normalizeMasterAccountCode(code string) string {
	code = strings.ToUpper(strings.TrimSpace(code))
	if code == "" {
		return code
	}

	noSpace := strings.ReplaceAll(code, " ", "")
	r := []rune(noSpace)
	if len(r) < 7 {
		return code
	}

	main := r[:7]
	return string(main[:3]) + " " + string(main[3:])
}
