import os,sys,time,io,zipfile
from pathlib import Path
import pytest
from PIL import Image
from fastapi.testclient import TestClient

sys.path.insert(0,str(Path(__file__).resolve().parents[1]))
from app import main as studio

@pytest.fixture
def client(tmp_path,monkeypatch):
    monkeypatch.setattr(studio,'DATA',tmp_path)
    monkeypatch.setattr(studio,'MEDIA',tmp_path/'media')
    monkeypatch.setattr(studio,'DB',tmp_path/'studio.sqlite3')
    studio.MEDIA.mkdir(parents=True,exist_ok=True)
    monkeypatch.delenv('OPENAI_API_KEY',raising=False)
    with TestClient(studio.app) as c:
        yield c

def brand(c):
    r=c.post('/api/brands',json={'name':'Komunitas Chinese Indonesia','industry':'Komunitas','audience':'Anak muda','caption_prefix':'ketik " JOIN " untuk bergabung di Komunitas Chinese Indonesia! 🇨🇳🇮🇩','max_hashtags':5})
    assert r.status_code==200,r.text
    return r.json()

def wait_for(c,bid,timeout=30):
    until=time.time()+timeout
    while time.time()<until:
        b=c.get('/api/batches/'+bid).json()
        if b['status'] in ('completed','partial','failed','cancelled'):
            return b
        time.sleep(.25)
    raise AssertionError('Batch timed out')

def test_complete_offline_flow(client):
    b=brand(client)
    upload_img=Image.new('RGB',(1080,1350),'#bd2b4a');buffer=io.BytesIO();upload_img.save(buffer,'JPEG')
    r=client.post('/api/brands/'+b['id']+'/upload',data={'kind':'reference'},files={'file':('example.jpg',buffer.getvalue(),'image/jpeg')})
    assert r.status_code==200,r.text
    assert r.json()['brand']['reference_path']
    topics='Tradisi Chinese yang Paling Berkesan\nMarga dan Sejarah Keluarga\nMakanan Favorit Saat Imlek'
    result=client.post('/api/batches',json={'brand_id':b['id'],'count':3,'theme':'Budaya Chinese Indonesia','topics':topics,'mode':'template'})
    assert result.status_code==200,result.text
    bid=result.json()['id']
    batch=wait_for(client,bid)
    assert batch['status']=='completed',batch
    assert batch['completed']==3
    contents=client.get('/api/batches/'+bid+'/contents').json()
    assert len(contents)==3 and len({x['title'] for x in contents})==3
    for c in contents:
        assert c['caption'].startswith('ketik " JOIN "')
        assert c['caption'].count('#')<=5
        r=client.get('/api/contents/'+c['id']+'/download')
        assert r.status_code==200
        img=Image.open(io.BytesIO(r.content))
        assert img.size==(1080,1350)
    z=client.get('/api/batches/'+bid+'/download')
    assert z.status_code==200
    with zipfile.ZipFile(io.BytesIO(z.content)) as archive:
        files=archive.namelist()
        assert len([x for x in files if x.startswith('images/')])==3
        assert len([x for x in files if x.startswith('captions/')])==3
        assert 'content_overview.csv' in files and 'all_captions.txt' in files
    edit=client.put('/api/contents/'+contents[0]['id'],json={
        'title':'Judul yang Diedit', 'subtitle':'Isi subjudul baru', 'caption':'Caption hasil edit'})
    assert edit.status_code==200,edit.text
    assert edit.json()['title']=='Judul yang Diedit'
    assert Image.open(io.BytesIO(client.get('/api/contents/'+contents[0]['id']+'/download').content)).size==(1080,1350)

def test_invalid_manual_batch_and_no_fake_ai(client):
    b=brand(client)
    response=client.post('/api/batches',json={'brand_id':b['id'],'count':3,'topics':'Satu\nDua','mode':'template'})
    assert response.status_code==422
    response=client.post('/api/batches',json={'brand_id':b['id'],'count':3,'topics':'Satu\nSatu\nDua','mode':'template'})
    assert response.status_code==422
    response=client.post('/api/batches',json={'brand_id':b['id'],'count':1,'mode':'ai'})
    assert response.status_code==422
    assert 'OPENAI_API_KEY' in response.text

def test_duplicate_detector():
    assert not studio.unique_title('Marga Sama Apakah Saudara?',['Marga sama apakah saudara?'])
    assert studio.unique_title('Belajar Membuat Website',['Tradisi Festival Kue Bulan'])

def test_visual_difference_hash():
    from app import graphics
    im=Image.new('RGB',(200,200),'#222222')
    d=io.BytesIO();im.save(d,'PNG')
    assert graphics.hash_distance(graphics.perceptual_dhash(d.getvalue()),graphics.perceptual_dhash(d.getvalue()))==0
