#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
FTP Otomatik Senkronizasyon Script'i

Kullanım:
    python scripts/ftp-sync.py upload    - Tüm dosyaları yükle, sonra otomatik watch mode'a geç
    python scripts/ftp-sync.py upload --no-watch  - Sadece yükle, watch mode'a geçme
    python scripts/ftp-sync.py watch    - Sadece dosya değişikliklerini izle (watch mode)
"""

import os
import sys
import time
import ftplib
import argparse
from pathlib import Path
from datetime import datetime

# Windows konsol encoding sorununu çöz
if sys.platform == 'win32':
    import io
    sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace')
    sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8', errors='replace')

class FTPSync:
    def __init__(self):
        self.host = '135.125.24.173'
        self.user = 'webviewolustur'
        self.passwd = 'CNDQWER123/*'
        self.remote_dir = '/public_html'
        self.local_dir = Path(__file__).parent.parent.resolve()
        self.conn = None
        
        self.ignore_patterns = [
            '.git',
            '.vscode',
            'node_modules',
            # 'vendor',  # vendor klasörü FTP ile yüklenecek
            '.env',
            '.log',
            'uploads',
            '.DS_Store',
            'Thumbs.db',
            # 'composer.lock',  # composer.lock da yüklenecek
            '.gitignore',
            '.gitattributes',
            '__pycache__',
            '*.pyc',
            '.python-version',
        ]
    
    def connect(self):
        """FTP bağlantısı kur"""
        try:
            self.conn = ftplib.FTP()
            self.conn.connect(self.host, 21)
            self.conn.login(self.user, self.passwd)
            self.conn.set_pasv(True)  # Passive mode
            print("[OK] FTP baglantisi kuruldu")
            return True
        except Exception as e:
            print(f"[HATA] FTP baglanti hatasi: {e}")
            return False
    
    def disconnect(self):
        """FTP bağlantısını kapat"""
        if self.conn:
            try:
                self.conn.quit()
                print("[OK] FTP baglantisi kapatildi")
            except:
                self.conn.close()
    
    def should_ignore(self, file_path):
        """Dosyanın yüklenmemesi gerekip gerekmediğini kontrol et"""
        relative_path = str(file_path.relative_to(self.local_dir))
        
        for pattern in self.ignore_patterns:
            if pattern in relative_path:
                return True
        
        # .env dosyasını kontrol et
        if file_path.name == '.env':
            return True
        
        return False
    
    def create_remote_dir(self, remote_path):
        """Uzak sunucuda dizin oluştur"""
        if not remote_path or remote_path == '.' or remote_path == '/':
            return
        
        # Dizin yolunu temizle ve normalize et
        remote_path = remote_path.replace('\\', '/')
        if remote_path.startswith('/'):
            # Absolute path - public_html ile başlamalı
            if not remote_path.startswith('/public_html'):
                remote_path = '/public_html' + remote_path
        else:
            # Relative path
            remote_path = '/public_html/' + remote_path
        
        dirs = [d for d in remote_path.split('/') if d]
        current_path = ''
        
        for dir_name in dirs:
            if not dir_name:
                continue
            current_path = current_path + '/' + dir_name if current_path else '/' + dir_name
            
            try:
                # Dizinin var olup olmadığını kontrol et
                self.conn.cwd(current_path)
                self.conn.cwd('/')  # Root'a dön
            except:
                # Dizin yok veya dosya olarak var, oluştur
                try:
                    # Önce dosya olarak varsa silmeyi dene
                    try:
                        self.conn.delete(current_path)
                        print(f"[OK] Dosya silindi (klasore donusturuluyor): {current_path}")
                    except:
                        pass  # Dosya yok, sorun değil
                    
                    # Klasörü oluştur
                    self.conn.mkd(current_path)
                    print(f"[OK] Dizin olusturuldu: {current_path}")
                except Exception as e:
                    # Dizin zaten var olabilir veya başka bir hata
                    # Eğer "Not a directory" hatası varsa, dosyayı silip tekrar dene
                    if 'Not a directory' in str(e) or '550' in str(e):
                        try:
                            # Dosyayı sil
                            self.conn.delete(current_path)
                            # Tekrar klasör oluştur
                            self.conn.mkd(current_path)
                            print(f"[OK] Dosya silindi ve klasor olusturuldu: {current_path}")
                        except:
                            pass
                    pass
    
    def upload_file(self, local_file, remote_file):
        """Dosyayı FTP'ye yükle"""
        try:
            # Sadece dosyaları yükle, klasörleri değil
            if not local_file.is_file():
                return False
            
            remote_dir = os.path.dirname(remote_file)
            if remote_dir and remote_dir != '/':
                self.create_remote_dir(remote_dir)
            
            # Tüm dosyaları binary mode ile yükle (daha güvenli)
            # Text dosyalar da binary olarak yüklenebilir, sorun çıkmaz
            with open(local_file, 'rb') as f:
                self.conn.storbinary(f'STOR {remote_file}', f)
            
            print(f"[OK] Yuklendi: {remote_file}")
            return True
            
        except Exception as e:
            print(f"[HATA] ({remote_file}): {e}")
            return False
    
    def upload_all(self, auto_watch=False):
        """Tüm dosyaları yükle"""
        if not self.connect():
            return
        
        print("\n[UPLOAD] Tum dosyalar yukleniyor...\n")
        
        uploaded = 0
        skipped = 0
        
        # Tüm dosyaları tara
        for root, dirs, files in os.walk(self.local_dir):
            # .git gibi klasörleri atla
            dirs[:] = [d for d in dirs if not any(ignore in d for ignore in self.ignore_patterns)]
            
            for file in files:
                local_file = Path(root) / file
                
                if self.should_ignore(local_file):
                    skipped += 1
                    continue
                
                # Relative path oluştur
                relative_path = local_file.relative_to(self.local_dir)
                relative_path_str = str(relative_path).replace('\\', '/')
                # Remote path'i düzgün birleştir
                remote_file = '/public_html/' + relative_path_str
                
                if self.upload_file(local_file, remote_file):
                    uploaded += 1
        
        print(f"\n[OK] Ilk yukleme tamamlandi!")
        print(f"   Yuklenen: {uploaded} dosya")
        print(f"   Atlanan: {skipped} dosya\n")
        
        self.disconnect()
        
        # Eğer auto_watch True ise, watch mode'a geç
        if auto_watch:
            print("[WATCH] Otomatik izleme moduna geciliyor...\n")
            self.watch()
    
    def watch(self):
        """Dosya değişikliklerini izle ve otomatik yükle"""
        print("[WATCH] Dosya degisiklikleri izleniyor...")
        print("   Her degisiklik otomatik olarak yuklenecek")
        print("   Durdurmak icin Ctrl+C\n")
        
        last_check = {}
        connection_established = False
        
        while True:
            try:
                # Her döngüde bağlantıyı kontrol et ve gerekirse yeniden kur
                if not connection_established or not self.conn:
                    if not self.connect():
                        print("[UYARI] Baglanti kurulamadi, 5 saniye sonra tekrar denenecek...")
                        time.sleep(5)
                        continue
                    connection_established = True
                
                # Tüm dosyaları tara
                for root, dirs, files in os.walk(self.local_dir):
                    # .git gibi klasörleri atla
                    dirs[:] = [d for d in dirs if not any(ignore in d for ignore in self.ignore_patterns)]
                    
                    for file in files:
                        local_file = Path(root) / file
                        
                        if self.should_ignore(local_file):
                            continue
                        
                        try:
                            # Dosya değişiklik zamanını kontrol et
                            mtime = local_file.stat().st_mtime
                            relative_path = str(local_file.relative_to(self.local_dir))
                            
                            # Değişiklik kontrolü
                            if relative_path not in last_check or last_check[relative_path] < mtime:
                                relative_path_str = relative_path.replace('\\', '/')
                                # Remote path'i düzgün birleştir
                                remote_file = '/public_html/' + relative_path_str
                                
                                print(f"[DEGISIKLIK] [{datetime.now().strftime('%H:%M:%S')}] {relative_path}")
                                
                                # Bağlantıyı kontrol et, gerekirse yeniden kur
                                try:
                                    self.conn.pwd()  # Bağlantıyı test et
                                except:
                                    if not self.connect():
                                        print("[UYARI] Baglanti hatasi, tekrar denenecek...")
                                        connection_established = False
                                        break
                                
                                if self.upload_file(local_file, remote_file):
                                    last_check[relative_path] = mtime
                        except FileNotFoundError:
                            # Dosya silinmiş olabilir, atla
                            continue
                        except Exception as e:
                            print(f"[UYARI] Dosya kontrol hatasi: {e}")
                            continue
                
            except KeyboardInterrupt:
                print("\n\n[DURDURULDU]")
                self.disconnect()
                break
            except Exception as e:
                print(f"[HATA] {e}")
                connection_established = False
                self.disconnect()
                time.sleep(2)
            
            # 2 saniye bekle
            time.sleep(2)


def main():
    parser = argparse.ArgumentParser(description='FTP Otomatik Senkronizasyon')
    parser.add_argument('command', choices=['upload', 'watch'], 
                       help='Komut: upload (tüm dosyalar, sonra otomatik watch) veya watch (sadece izleme)')
    parser.add_argument('--no-watch', action='store_true',
                       help='Upload sonrası watch mode\'a geçme (sadece upload yap)')
    
    args = parser.parse_args()
    
    sync = FTPSync()
    
    try:
        if args.command == 'watch':
            sync.watch()
        else:
            # upload komutu: önce tüm dosyaları yükle, sonra otomatik watch mode'a geç
            sync.upload_all(auto_watch=not args.no_watch)
    except KeyboardInterrupt:
        print("\n\n[DURDURULDU] Islem durduruldu")
        sys.exit(0)
    except Exception as e:
        print(f"[HATA] {e}")
        sys.exit(1)


if __name__ == '__main__':
    main()

