# -*- coding: utf-8 -*-
"""
SATIRLARI OZGUN TRENDYOL SABLONUNUN ICINE GOM

NEDEN BU DOSYA VAR
Sablonu openpyxl ile acip kaydetmek Trendyol yukleyicisinde
"Excel dosyasinda kayit edilecek satir bulunamadi" hatasi verdi.
Zip icerigi karsilastirildi, openpyxl'in DUSURDUGU parcalar:

    xl/drawings/drawing1.xml + _rels      (Trendyol logosu)
    xl/media/image1.png
    xl/printerSettings/printerSettings1.bin
    xl/sharedStrings.xml

Ayrica hucre TIPLERI degisti: ozgunde Kategori metin ('2797'),
openpyxl'de sayi oldu.

COZUM: sablonu hic yeniden yazmamak. Zip'i acip YALNIZ ilgili
sayfalarin sheetData bolumunu degistirip diger butun parcalari
BAYT BAYT ayni kopyalamak. Boylece Trendyol kendi dosyasini
gorur, icinde yalnizca satirlar eklenmis olur.

Baslik satiri (row 1) ozgun XML'den AYNEN korunur - stil kimlikleri
(s="38" gibi) ve inlineStr yapisi bozulmaz.

Hucre tipleri ozgunun kendi kuralina uyduruldu:
  metin  -> t="inlineStr"  (Kategori dahil; ozgunde de metindi)
  sayi   -> ciplak <v>     (fiyat, stok, KDV, desi - xlsx sayilari
            her zaman nokta ile saklanir, yerel ayardan etkilenmez)

    python xlsx_enjekte.py
"""
import io, os, re, json, zipfile, shutil

SABLON = r'C:\Users\Mikro Pc\Desktop\urun-olusturma-1402308.xlsx'
CIKTI  = r'C:\Users\Mikro Pc\Desktop\Trendyol-Urunler-YUKLE.xlsx'
SATIR  = r'C:\Users\MIKROP~1\AppData\Local\Temp\claude\ty_satirlar.json'

# Sayi olarak yazilacak kolonlar. Digerleri metin.
SAYI_KOLON = set([
    'Piyasa Satış Fiyatı (KDV Dahil)',
    'Ürün Stok Adedi', 'KDV Oranı', 'ÖTV Oranı', 'Desi',
    'Sevkiyat Süresi',
])
SAYI_ONEK = "Trendyol'da Satılacak Fiyat"   # basligi uzun, onekle yakala


def kolon_adi(i):
    """1 -> A, 27 -> AA"""
    s = ''
    while i > 0:
        i, k = divmod(i - 1, 26)
        s = chr(65 + k) + s
    return s


def kacis(s):
    s = str(s)
    # XML 1.0'da yasak kontrol karakterlerini at
    s = ''.join(ch for ch in s if ch in '\t\n\r' or ord(ch) >= 32)
    return (s.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;'))


def hucre(ref, deger, sayi_mi):
    if sayi_mi:
        # sayiyi nokta ile, gereksiz sifir olmadan
        d = float(deger)
        v = ('%d' % int(round(d))) if abs(d - round(d)) < 1e-9 else ('%.2f' % d)
        return '<c r="%s"><v>%s</v></c>' % (ref, v)
    return '<c r="%s" t="inlineStr"><is><t>%s</t></is></c>' % (ref, kacis(deger))


def main():
    satirlar = json.load(io.open(SATIR, encoding='utf-8'))
    z = zipfile.ZipFile(SABLON)
    parcalar = dict((n, z.read(n)) for n in z.namelist())
    sira = z.namelist()

    wbx = parcalar['xl/workbook.xml'].decode('utf-8')
    relx = parcalar['xl/_rels/workbook.xml.rels'].decode('utf-8')
    rmap = dict(re.findall(r'Id="([^"]+)"[^>]*?Target="([^"]+)"', relx))

    # sayfa adi (XML kacisli) -> parca yolu
    yol = {}
    for m in re.finditer(r'<sheet[^>]*name="([^"]+)"[^>]*?r:id="([^"]+)"[^>]*/>', wbx):
        ad = (m.group(1).replace('&amp;', '&').replace('&lt;', '<')
              .replace('&gt;', '>').replace('&quot;', '"').replace('&apos;', "'"))
        t = rmap.get(m.group(2), '')
        yol[ad] = 'xl/' + t.lstrip('/')
    # bazi sablonlarda r:id name'den ONCE geliyor - ikinci desen
    for m in re.finditer(r'<sheet[^>]*?r:id="([^"]+)"[^>]*name="([^"]+)"[^>]*/>', wbx):
        ad = (m.group(2).replace('&amp;', '&').replace('&lt;', '<')
              .replace('&gt;', '>').replace('&quot;', '"').replace('&apos;', "'"))
        yol.setdefault(ad, 'xl/' + rmap.get(m.group(1), '').lstrip('/'))

    print('=== SAYFA -> XML ===')
    islenen = 0
    for sad, kayitlar in satirlar.items():
        if not kayitlar:
            print('  %-40s satir yok, atlandi' % sad[:40]); continue
        sp = yol.get(sad)
        if not sp or sp not in parcalar:
            print('  %-40s XML BULUNAMADI (%r)' % (sad[:40], sp)); continue

        x = parcalar[sp].decode('utf-8')
        m = re.search(r'<sheetData>(.*?)</sheetData>', x, re.S)
        if not m:
            print('  %-40s sheetData yok' % sad[:40]); continue
        icerik = m.group(1)

        # baslik satirini AYNEN koru + basliklarin kolon numaralarini oku
        b = re.search(r'<row[^>]*r="1"[^>]*>.*?</row>', icerik, re.S)
        if not b:
            print('  %-40s baslik satiri yok' % sad[:40]); continue
        baslik_xml = b.group(0)
        K = {}
        for cm in re.finditer(r'<c r="([A-Z]+)1"[^>]*>(.*?)</c>', baslik_xml, re.S):
            t = re.search(r'<t[^>]*>(.*?)</t>', cm.group(2), re.S)
            if not t: continue
            ad2 = (t.group(1).replace('&amp;', '&').replace('&lt;', '<')
                   .replace('&gt;', '>')).strip()
            K[ad2] = cm.group(1)

        yeni = [baslik_xml]
        enSagIdx = 0
        for i, kayit in enumerate(kayitlar, start=2):
            hs = []
            for bas, deger in kayit.items():
                harf = K.get(bas)
                if not harf:
                    continue
                sayi = (bas in SAYI_KOLON) or bas.startswith(SAYI_ONEK)
                hs.append((harf, hucre('%s%d' % (harf, i), deger, sayi)))
            # hucreler kolon sirasinda olmali
            hs.sort(key=lambda p: (len(p[0]), p[0]))
            if hs:
                son = hs[-1][0]
                enSagIdx = max(enSagIdx, len(son))
            yeni.append('<row r="%d">%s</row>' % (i, ''.join(h[1] for h in hs)))

        yeniIcerik = '\n'.join(yeni)
        x2 = x[:m.start(1)] + yeniIcerik + x[m.end(1):]

        # dimension guncelle
        sonSatir = len(kayitlar) + 1
        # en sagdaki kolon: once uzunluga sonra alfabetik (Z < AA)
        sonKolon = max(K.values(), key=lambda h: (len(h), h))
        x2 = re.sub(r'<dimension ref="[^"]*"\s*/>',
                    '<dimension ref="A1:%s%d"/>' % (sonKolon, sonSatir), x2, count=1)

        parcalar[sp] = x2.encode('utf-8')
        print('  %-40s %s  %d satir yazildi (A1:%s%d)'
              % (sad[:40], sp, len(kayitlar), sonKolon, sonSatir))
        islenen += 1

    if os.path.exists(CIKTI): os.remove(CIKTI)
    zo = zipfile.ZipFile(CIKTI, 'w', zipfile.ZIP_DEFLATED)
    for n in sira:                      # ozgun sirayi koru
        zo.writestr(n, parcalar[n])
    zo.close()

    z2 = zipfile.ZipFile(CIKTI)
    print('\nislenen sayfa: %d' % islenen)
    print('parca sayisi: sablon %d -> cikti %d  (esit olmali)'
          % (len(sira), len(z2.namelist())))
    eksik = set(sira) - set(z2.namelist())
    print('eksik parca: %s' % (sorted(eksik) if eksik else 'YOK'))
    print('Cikti: %s  (%s bayt)' % (CIKTI, format(os.path.getsize(CIKTI), ',')))


if __name__ == '__main__':
    main()
