#!/bin/bash

# ptyFileMove
# 다양한 조건으로 파일을 검색하고 지정한 디렉토리로 이동하는 스크립트
# 사용법:
#   ./ptyFileMove "*.log" "./backup"           # 현재 디렉토리의 .log 파일을 ./backup으로 이동
#   ./ptyFileMove "*_eflaw_*" "../data_eflaw"  # _eflaw_가 포함된 파일을 ../data_eflaw로 이동
#   ./ptyFileMove "*.txt" "/backup" -r -d 10   # 하위 디렉토리까지 .txt 파일 중 10일 이상 지난 파일을 /backup으로 이동

show_usage() {
    echo "사용법: $0 <검색패턴> <목적지디렉토리> [옵션]"
    echo ""
    echo "필수 인자:"
    echo "  검색패턴          검색할 파일 패턴 (예: *.log, *_eflaw_*, ./* 등)"
    echo "                    ./*  : 현재 디렉토리의 모든 파일"
    echo "                    *.log : 현재 디렉토리의 .log 파일"
    echo "                    /var/log/*.log : /var/log의 .log 파일"
    echo "  목적지디렉토리    파일을 이동할 대상 디렉토리"
    echo ""
    echo "검색 조건 옵션:"
    echo "  -d 일수           지정한 일수보다 오래된 파일 검색"
    echo "  -h 시간           지정한 시간보다 오래된 파일 검색"
    echo "  -zerofiles        0바이트 파일 검색"
    echo "  -size 크기        특정 크기의 파일 검색 (예: +10M, -1k, 100c)"
    echo "                    (+: 초과, -: 미만, 단위: c=byte, k=KB, M=MB, G=GB)"
    echo "  -user 사용자      특정 사용자 소유 파일 검색"
    echo "  -perm 권한        특정 권한의 파일 검색 (예: 777, 644)"
    echo ""
    echo "공통 옵션:"
    echo "  -r                하위 디렉토리까지 재귀적으로 검색"
    echo "  -t 타입           파일 타입 (f: 파일만, d: 디렉토리만, l: 심볼릭링크)"
    echo "  -s                파일 크기와 함께 표시"
    echo "  -l                상세 정보 표시 (ls -lh 형식)"
    echo "  -maxdepth N       검색 깊이 제한 (1: 현재 디렉토리만)"
    echo "  -count            개수만 표시"
    echo "  --force           확인 없이 즉시 이동"
    echo "  --copy            이동 대신 복사"
    echo ""
    echo "예제:"
    echo "  $0 '*.log' './backup'                    # 현재 디렉토리의 .log 파일을 ./backup으로 이동"
    echo "  $0 '*_eflaw_*' '../data_eflaw'           # _eflaw_가 포함된 파일을 ../data_eflaw로 이동"
    echo "  $0 '*.log' '/backup' -r -d 10            # 하위까지 .log 파일 중 10일 이상 지난 파일을 /backup으로 이동"
    echo "  $0 '*.txt' './archive' -h 24             # 현재 디렉토리의 .txt 파일 중 24시간 이상 지난 파일을 ./archive로 이동"
    echo "  $0 './*' './backup' -zerofiles           # 현재 디렉토리의 모든 0바이트 파일을 ./backup으로 이동"
    echo "  $0 '*.log' '/backup' -r -d 30 --force    # 30일 이상 지난 .log 파일을 확인 없이 /backup으로 이동"
    echo "  $0 '*.tmp' './backup' -size +100M --copy # 100MB 이상의 .tmp 파일을 ./backup으로 복사"
    exit 1
}

# 인자 개수 확인
if [ $# -lt 2 ]; then
    echo "오류: 검색 패턴과 목적지 디렉토리를 지정해야 합니다."
    echo ""
    show_usage
fi

# 첫 번째 인자가 옵션인지 확인
if [[ "$1" == -* ]]; then
    echo "오류: 첫 번째 인자는 검색 패턴이어야 합니다."
    echo ""
    show_usage
fi

# 두 번째 인자가 옵션인지 확인
if [[ "$2" == -* ]]; then
    echo "오류: 두 번째 인자는 목적지 디렉토리여야 합니다."
    echo ""
    show_usage
fi

# 첫 번째, 두 번째 인자 설정
SEARCH_PATTERN="$1"
DEST_DIR="$2"
shift 2

# 목적지 디렉토리 확인 및 생성
if [ ! -d "$DEST_DIR" ]; then
    read -p "목적지 디렉토리 '$DEST_DIR'가 존재하지 않습니다. 생성하시겠습니까? (y/N): " -n 1 -r
    echo ""
    if [[ $REPLY =~ ^[Yy]$ ]]; then
        mkdir -p "$DEST_DIR"
        if [ $? -ne 0 ]; then
            echo "오류: 목적지 디렉토리 생성에 실패했습니다."
            exit 1
        fi
        echo "목적지 디렉토리 '$DEST_DIR'를 생성했습니다."
    else
        echo "작업이 취소되었습니다."
        exit 1
    fi
fi

# 목적지 디렉토리를 절대 경로로 변환
DEST_DIR=$(cd "$DEST_DIR" && pwd)

# 패턴에서 경로와 파일명 분리
if [[ "$SEARCH_PATTERN" == */* ]]; then
    # 경로가 포함된 경우
    SEARCH_PATH="${SEARCH_PATTERN%/*}"
    FILE_PATTERN="${SEARCH_PATTERN##*/}"
    # 경로가 비어있으면 루트로 설정
    if [ -z "$SEARCH_PATH" ]; then
        SEARCH_PATH="/"
    fi
else
    # 경로가 없는 경우 현재 디렉토리
    SEARCH_PATH="."
    FILE_PATTERN="$SEARCH_PATTERN"
fi

# 기본값 설정
DAYS=""
HOURS=""
FILE_TYPE=""
SHOW_SIZE=false
SHOW_DETAIL=false
SHOW_COUNT=false
SEARCH_MODE=""
FILE_SIZE=""
FILE_USER=""
FILE_PERM=""
MAX_DEPTH="1"
RECURSIVE=false
MOVE_FORCE=false
COPY_MODE=false

# 옵션 파싱
while [[ $# -gt 0 ]]; do
    case $1 in
        -d)
            DAYS="$2"
            SEARCH_MODE="old"
            shift 2
            ;;
        -h)
            HOURS="$2"
            SEARCH_MODE="old"
            shift 2
            ;;
        -zerofiles)
            SEARCH_MODE="zero"
            shift
            ;;
        -size)
            FILE_SIZE="$2"
            SEARCH_MODE="size"
            shift 2
            ;;
        -user)
            FILE_USER="$2"
            SEARCH_MODE="user"
            shift 2
            ;;
        -perm)
            FILE_PERM="$2"
            SEARCH_MODE="perm"
            shift 2
            ;;
        -r)
            RECURSIVE=true
            MAX_DEPTH=""
            shift
            ;;
        -t)
            FILE_TYPE="$2"
            shift 2
            ;;
        -s)
            SHOW_SIZE=true
            shift
            ;;
        -l)
            SHOW_DETAIL=true
            shift
            ;;
        -maxdepth)
            MAX_DEPTH="$2"
            RECURSIVE=false
            shift 2
            ;;
        -count)
            SHOW_COUNT=true
            shift
            ;;
        --force)
            MOVE_FORCE=true
            shift
            ;;
        --copy)
            COPY_MODE=true
            shift
            ;;
        -help|--help)
            show_usage
            ;;
        *)
            echo "오류: 알 수 없는 옵션: $1"
            echo ""
            show_usage
            ;;
    esac
done

# 검색 모드가 지정되지 않은 경우 기본 검색 모드로 설정
if [ -z "$SEARCH_MODE" ]; then
    SEARCH_MODE="pattern"
fi

# 검색 경로 확인
if [ ! -d "$SEARCH_PATH" ]; then
    echo "오류: 검색 경로 '$SEARCH_PATH'가 존재하지 않습니다."
    exit 1
fi

# 숫자 유효성 검사
if [ -n "$DAYS" ]; then
    if ! [[ "$DAYS" =~ ^[0-9]+$ ]]; then
        echo "오류: 일수는 숫자여야 합니다."
        exit 1
    fi
fi

if [ -n "$HOURS" ]; then
    if ! [[ "$HOURS" =~ ^[0-9]+$ ]]; then
        echo "오류: 시간은 숫자여야 합니다."
        exit 1
    fi
fi

# find 명령어 옵션 구성
FIND_CMD="find \"$SEARCH_PATH\""

# 최대 깊이 설정 (-r 옵션이 없고 -maxdepth도 지정되지 않은 경우 기본값 1)
if [ -n "$MAX_DEPTH" ]; then
    FIND_CMD="$FIND_CMD -maxdepth $MAX_DEPTH"
fi

# 파일 패턴 적용
if [ "$FILE_PATTERN" != "*" ]; then
    FIND_CMD="$FIND_CMD -name \"$FILE_PATTERN\""
fi

# 파일 타입 옵션 (기본값: 파일만)
if [ -z "$FILE_TYPE" ]; then
    FIND_CMD="$FIND_CMD -type f"
elif [ "$FILE_TYPE" = "f" ]; then
    FIND_CMD="$FIND_CMD -type f"
elif [ "$FILE_TYPE" = "d" ]; then
    FIND_CMD="$FIND_CMD -type d"
elif [ "$FILE_TYPE" = "l" ]; then
    FIND_CMD="$FIND_CMD -type l"
fi

# 검색 조건 설정
SEARCH_DESC=""
case $SEARCH_MODE in
    pattern)
        SEARCH_DESC="파일명 패턴 매칭"
        ;;
    old)
        if [ -n "$DAYS" ] && [ -n "$HOURS" ]; then
            echo "오류: -d와 -h 옵션은 동시에 사용할 수 없습니다."
            exit 1
        fi
        if [ -n "$DAYS" ]; then
            FIND_CMD="$FIND_CMD -mtime +$DAYS"
            SEARCH_DESC="${DAYS}일 이상 지난 파일"
        else
            MINUTES=$((HOURS * 60))
            FIND_CMD="$FIND_CMD -mmin +$MINUTES"
            SEARCH_DESC="${HOURS}시간 이상 지난 파일"
        fi
        ;;
    zero)
        FIND_CMD="$FIND_CMD -type f -size 0"
        SEARCH_DESC="0바이트 파일"
        ;;
    size)
        FIND_CMD="$FIND_CMD -size $FILE_SIZE"
        SEARCH_DESC="크기: $FILE_SIZE"
        ;;
    user)
        FIND_CMD="$FIND_CMD -user $FILE_USER"
        SEARCH_DESC="소유자: $FILE_USER"
        ;;
    perm)
        FIND_CMD="$FIND_CMD -perm $FILE_PERM"
        SEARCH_DESC="권한: $FILE_PERM"
        ;;
esac

# 헤더 출력
echo "============================================"
if [ "$COPY_MODE" = true ]; then
    echo "파일 복사 작업"
else
    echo "파일 이동 작업"
fi
echo "============================================"
echo "검색 패턴: $SEARCH_PATTERN"
echo "검색 경로: $SEARCH_PATH"
echo "목적지: $DEST_DIR"
echo "검색 조건: $SEARCH_DESC"
if [ "$RECURSIVE" = true ]; then
    echo "재귀 검색: 예 (모든 하위 디렉토리)"
elif [ -n "$MAX_DEPTH" ]; then
    echo "검색 깊이: $MAX_DEPTH"
fi
if [ -n "$FILE_TYPE" ]; then
    case $FILE_TYPE in
        f) echo "파일 타입: 파일만" ;;
        d) echo "파일 타입: 디렉토리만" ;;
        l) echo "파일 타입: 심볼릭링크만" ;;
    esac
fi
echo "============================================"
echo ""

# 개수만 표시하는 경우
if [ "$SHOW_COUNT" = true ]; then
    COUNT=$(eval $FIND_CMD 2>/dev/null | wc -l)
    echo "총 ${COUNT}개의 항목을 찾았습니다."
    exit 0
fi

# 파일 찾기 및 결과 출력
echo "대상 파일 목록:"
echo "============================================"
if [ "$SHOW_DETAIL" = true ]; then
    # 상세 정보 표시
    eval $FIND_CMD -exec ls -lhd {} \; 2>/dev/null | sort -k9
    COUNT=$(eval $FIND_CMD 2>/dev/null | wc -l)
elif [ "$SHOW_SIZE" = true ]; then
    # 크기와 함께 표시
    eval $FIND_CMD -exec ls -lhd {} \; 2>/dev/null | awk '{print $5 "\t" $9}' | sort -k2
    COUNT=$(eval $FIND_CMD 2>/dev/null | wc -l)
else
    # 기본: 경로만 표시
    eval $FIND_CMD 2>/dev/null | sort
    COUNT=$(eval $FIND_CMD 2>/dev/null | wc -l)
fi

# 결과 요약
echo ""
echo "============================================"
echo "총 ${COUNT}개의 항목을 찾았습니다."
echo "============================================"

# 총 크기 계산 (파일인 경우만)
if [ "$FILE_TYPE" = "f" ] || [ -z "$FILE_TYPE" ] || [ "$SEARCH_MODE" = "zero" ] || [ "$SEARCH_MODE" = "size" ]; then
    TOTAL_SIZE=$(eval $FIND_CMD -type f -exec du -cb {} + 2>/dev/null | tail -1 | cut -f1)
    if [ -n "$TOTAL_SIZE" ] && [ "$TOTAL_SIZE" != "0" ]; then
        # 바이트를 사람이 읽기 쉬운 형식으로 변환
        TOTAL_SIZE_HUMAN=$(numfmt --to=iec-i --suffix=B $TOTAL_SIZE 2>/dev/null || echo "${TOTAL_SIZE} bytes")
        echo "총 파일 크기: $TOTAL_SIZE_HUMAN"
        echo "============================================"
    fi
fi

# 이동/복사 처리
if [ "$COUNT" -eq 0 ]; then
    echo ""
    if [ "$COPY_MODE" = true ]; then
        echo "복사할 항목이 없습니다."
    else
        echo "이동할 항목이 없습니다."
    fi
    exit 0
fi

# 강제 모드가 아닌 경우 확인 받기
PROCEED_MOVE=false
if [ "$MOVE_FORCE" = true ]; then
    PROCEED_MOVE=true
    echo ""
    echo "============================================"
    if [ "$COPY_MODE" = true ]; then
        echo "강제 모드: ${COUNT}개 항목을 복사합니다."
    else
        echo "강제 모드: ${COUNT}개 항목을 이동합니다."
    fi
    echo "============================================"
else
    echo ""
    echo "============================================"
    if [ "$COPY_MODE" = true ]; then
        echo "위의 ${COUNT}개 항목을 '$DEST_DIR'로 복사하시겠습니까?"
    else
        echo "위의 ${COUNT}개 항목을 '$DEST_DIR'로 이동하시겠습니까?"
    fi
    echo "============================================"
    read -p "진행하시겠습니까? (y/N): " -n 1 -r
    echo ""
    if [[ $REPLY =~ ^[Yy]$ ]]; then
        PROCEED_MOVE=true
    fi
fi

if [ "$PROCEED_MOVE" = true ]; then
    echo ""
    if [ "$COPY_MODE" = true ]; then
        echo "복사 중..."
    else
        echo "이동 중..."
    fi
    MOVED_COUNT=0
    FAILED_COUNT=0

    # 각 파일/디렉토리 이동/복사
    while IFS= read -r item; do
        # 파일명 추출
        filename=$(basename "$item")

        if [ "$COPY_MODE" = true ]; then
            # 복사 모드
            if cp -p "$item" "$DEST_DIR/$filename" 2>/dev/null; then
                echo "복사됨: $item -> $DEST_DIR/$filename"
                ((MOVED_COUNT++))
            else
                echo "복사 실패: $item (권한 부족 또는 대상에 동일 파일 존재)"
                ((FAILED_COUNT++))
            fi
        else
            # 이동 모드
            if mv "$item" "$DEST_DIR/$filename" 2>/dev/null; then
                echo "이동됨: $item -> $DEST_DIR/$filename"
                ((MOVED_COUNT++))
            else
                echo "이동 실패: $item (권한 부족 또는 대상에 동일 파일 존재)"
                ((FAILED_COUNT++))
            fi
        fi
    done < <(eval $FIND_CMD 2>/dev/null)

    echo ""
    echo "============================================"
    if [ "$COPY_MODE" = true ]; then
        echo "복사 완료: ${MOVED_COUNT}개 항목"
    else
        echo "이동 완료: ${MOVED_COUNT}개 항목"
    fi
    if [ "$FAILED_COUNT" -gt 0 ]; then
        if [ "$COPY_MODE" = true ]; then
            echo "복사 실패: ${FAILED_COUNT}개 항목"
        else
            echo "이동 실패: ${FAILED_COUNT}개 항목"
        fi
    fi
    echo "============================================"
else
    echo ""
    echo "작업이 취소되었습니다."
fi

exit 0
